Merge branch 'master' into penfield
authorJoseph Spiros <joseph.spiros@ithinksw.com>
Thu, 10 Jun 2010 08:36:35 +0000 (04:36 -0400)
committerJoseph Spiros <joseph.spiros@ithinksw.com>
Thu, 10 Jun 2010 08:36:35 +0000 (04:36 -0400)
models.py
templatetags/containers.py

index e32265d..eb6ebc0 100644 (file)
--- a/models.py
+++ b/models.py
@@ -21,6 +21,7 @@ from django.template.loader_tags import ExtendsNode, ConstantIncludeNode, Includ
 from django.template.loader import get_template
 from django.http import Http404, HttpResponse, HttpResponseServerError, HttpResponseRedirect
 from django.core.servers.basehttp import FileWrapper
+from django.conf import settings
 
 
 def register_value_model(model):
@@ -195,9 +196,18 @@ class TreeEntity(TreeModel, Entity):
                abstract = True
 
 
-class Node(TreeEntity):
+class InheritableTreeEntity(TreeEntity):
        instance_type = models.ForeignKey(ContentType, editable=False)
        
+       def save(self, force_insert=False, force_update=False):
+               if not hasattr(self, 'instance_type_ptr'):
+                       self.instance_type = ContentType.objects.get_for_model(self.__class__)
+               super(InheritableTreeEntity, self).save(force_insert, force_update)
+       
+       @property
+       def instance(self):
+               return self.instance_type.get_object_for_this_type(id=self.id)
+       
        def get_path(self, pathsep='/', field='slug'):
                path = getattr(self.instance, field, '?')
                parent = self.parent
@@ -207,15 +217,23 @@ class Node(TreeEntity):
                return path
        path = property(get_path)
        
-       def save(self, force_insert=False, force_update=False):
-               if not hasattr(self, 'instance_type_ptr'):
-                       self.instance_type = ContentType.objects.get_for_model(self.__class__)
-               super(Node, self).save(force_insert, force_update)
-       
        @property
-       def instance(self):
-               return self.instance_type.get_object_for_this_type(id=self.id)
+       def attributes(self):
+               if self.parent:
+                       return QuerySetMapper(self.instance.attribute_set, passthrough=self.parent.instance.attributes)
+               return QuerySetMapper(self.instance.attribute_set)
+
+       @property
+       def relationships(self):
+               if self.parent:
+                       return QuerySetMapper(self.instance.relationship_set, passthrough=self.parent.instance.relationships)
+               return QuerySetMapper(self.instance.relationship_set)
        
+       class Meta:
+               abstract = True
+
+
+class Node(InheritableTreeEntity):
        accepts_subpath = False
        
        def render_to_response(self, request, path=None, subpath=None):
@@ -244,7 +262,7 @@ class Redirect(Node):
                (302, 'Temporary'),
                (301, 'Permanent'),
        )
-       target = models.URLField()
+       target = models.URLField(help_text='Must be a valid, absolute URL (i.e. http://)')
        status_code = models.IntegerField(choices=STATUS_CODES, default=302, verbose_name='redirect type')
        
        def render_to_response(self, request, path=None, subpath=None):
@@ -268,8 +286,8 @@ class File(Node):
 class Template(TreeModel):
        name = models.CharField(max_length=255)
        documentation = models.TextField(null=True, blank=True)
-       mimetype = models.CharField(max_length=255, null=True, blank=True)
-       code = models.TextField()
+       mimetype = models.CharField(max_length=255, null=True, blank=True, help_text='Default: %s' % settings.DEFAULT_CONTENT_TYPE)
+       code = models.TextField(verbose_name='django template code')
        
        @property
        def origin(self):
@@ -292,7 +310,7 @@ class Template(TreeModel):
                                nodes = []
                                for node in nodelist:
                                        try:
-                                               for nodelist_name in ('nodelist', 'nodelist_loop', 'nodelist_empty', 'nodelist_true', 'nodelist_false'):
+                                               for nodelist_name in ('nodelist', 'nodelist_loop', 'nodelist_empty', 'nodelist_true', 'nodelist_false', 'nodelist_main'):
                                                        if hasattr(node, nodelist_name):
                                                                nodes.extend(nodelist_container_nodes(getattr(node, nodelist_name)))
                                                if isinstance(node, ContainerNode):
@@ -337,6 +355,11 @@ class Template(TreeModel):
 
 
 class Page(Node):
+       """
+       Represents an HTML page. The page will have a number of related Contentlets
+       depending on the template selected - but these will appear only after the
+       page has been saved with that template.
+       """
        template = models.ForeignKey(Template, related_name='pages')
        title = models.CharField(max_length=255)
        
index cc6b313..ca5e1e9 100644 (file)
@@ -9,45 +9,84 @@ register = template.Library()
 
 
 class ContainerNode(template.Node):
-       def __init__(self, name, references=None, as_var=None):
+       child_nodelists = ('nodelist_main', 'nodelist_empty',)
+       
+       def __init__(self, name, references=None, as_var=None, nodelist_main=None, nodelist_empty=None):
                self.name = name
                self.as_var = as_var
                self.references = references
+               
+               if nodelist_main is None:
+                       self.nodelist_main = template.NodeList()
+               else:
+                       self.nodelist_main = nodelist_main
+               
+               if nodelist_empty is None:
+                       self.nodelist_empty = template.NodeList()
+               else:
+                       self.nodelist_empty = nodelist_empty
+       
        def render(self, context):
                content = settings.TEMPLATE_STRING_IF_INVALID
                if 'page' in context:
-                       page = context['page']
-                       if self.references:
-                               try:
-                                       contentreference = page.contentreferences.get(name__exact=self.name, content_type=self.references)
-                                       content = contentreference.content
-                               except ObjectDoesNotExist:
-                                       pass
-                       else:
-                               try:
-                                       contentlet = page.contentlets.get(name__exact=self.name)
-                                       if contentlet.dynamic:
-                                               try:
-                                                       content = mark_safe(template.Template(contentlet.content, name=contentlet.name).render(context))
-                                               except template.TemplateSyntaxError, error:
-                                                       if settings.DEBUG:
-                                                               content = ('[Error parsing contentlet \'%s\': %s]' % self.name, error)
-                                       else:
-                                               content = contentlet.content
-                               except ObjectDoesNotExist:
-                                       pass
-               if content and self.as_var:
-                       context[self.as_var] = content
-                       return ''
+                       container_content = self.get_container_content(context['page'])
+               
+               if self.nodelist_main is None:
+                       self.nodelist_main
+                       if container_content and self.as_var:
+                               context[self.as_var] = container_content
+                               return ''
+                       return container_content
+               
+               if container_content:
+                       if self.as_var is None:
+                               self.as_var = self.name
+                       
+                       #make a new context 
+                       context.push()
+                       context[self.as_var] = container_content
+                       nodelist = template.NodeList()
+                       for node in self.nodelist_main:
+                               nodelist.append(node.render(context))
+                       context.pop()
+                       return nodelist.render(context)
+               
+               if self.nodelist_empty is not None:
+                       return self.nodelist_empty.render(context)
+               
+               return ''
+       
+       def get_container_content(self, page):
+               if self.references:
+                       try:
+                               contentreference = page.contentreferences.get(name__exact=self.name, content_type=self.references)
+                               content = contentreference.content
+                       except ObjectDoesNotExist:
+                               content = ''
+               else:
+                       try:
+                               contentlet = page.contentlets.get(name__exact=self.name)
+                               if contentlet.dynamic:
+                                       try:
+                                               content = mark_safe(template.Template(contentlet.content, name=contentlet.name).render(context))
+                                       except template.TemplateSyntaxError, error:
+                                               if settings.DEBUG:
+                                                       content = ('[Error parsing contentlet \'%s\': %s]' % self.name, error)
+                               else:
+                                       content = contentlet.content
+                       except ObjectDoesNotExist:
+                               content = ''
                return content
 
 
 def do_container(parser, token):
        """
-       {% container <name> [[references <type>] as <variable>] %}
+       {% container <name> [[references <type>] as <variable>] %} 
+       {% blockcontainer <name> [[references <type>] as <variable>] %} [ {% empty %} ] {% endblockcontainer %}
        """
        params = token.split_contents()
        if len(params) >= 2:
+               tag = params[0]
                name = params[1].strip('"')
                references = None
                as_var = None
@@ -60,19 +99,34 @@ def do_container(parser, token):
                                                app_label, model = remaining_tokens.pop(0).strip('"').split('.')
                                                references = ContentType.objects.get(app_label=app_label, model=model)
                                        except IndexError:
-                                               raise template.TemplateSyntaxError('"container" template tag option "references" requires an argument specifying a content type')
+                                               raise template.TemplateSyntaxError('"%s" template tag option "references" requires an argument specifying a content type' % tag)
                                        except ValueError:
-                                               raise template.TemplateSyntaxError('"container" template tag option "references" requires an argument of the form app_label.model (see django.contrib.contenttypes)')
+                                               raise template.TemplateSyntaxError('"%s" template tag option "references" requires an argument of the form app_label.model (see django.contrib.contenttypes)' % tag)
                                        except ObjectDoesNotExist:
-                                               raise template.TemplateSyntaxError('"container" template tag option "references" requires an argument of the form app_label.model which refers to an installed content type (see django.contrib.contenttypes)')
+                                               raise template.TemplateSyntaxError('"%s" template tag option "references" requires an argument of the form app_label.model which refers to an installed content type (see django.contrib.contenttypes)' % tag)
                                elif option_token == 'as':
                                        try:
                                                as_var = remaining_tokens.pop(0)
                                        except IndexError:
-                                               raise template.TemplateSyntaxError('"container" template tag option "as" requires an argument specifying a variable name')
+                                               raise template.TemplateSyntaxError('"%s" template tag option "as" requires an argument specifying a variable name' % tag)
                        if references and not as_var:
-                               raise template.TemplateSyntaxError('"container" template tags using "references" option require additional use of the "as" option specifying a variable name')
-               return ContainerNode(name, references, as_var)
+                               raise template.TemplateSyntaxError('"%s" template tags using "references" option require additional use of the "as" option specifying a variable name' % tag)
+               if tag == 'container':
+                       return ContainerNode(name, references, as_var)
+               
+               nodelist_main = parser.parse(('empty','endblockcontainer',))
+               token = parser.next_token()
+               
+               if token.contents == 'empty':
+                       nodelist_empty = parser.parse(('endblockcontainer',))
+                       parser.delete_first_token()
+               else:
+                       nodelist_empty = None
+               return ContainerNode(name, references, as_var, nodelist_main, nodelist_empty)
+               
        else: # error
-               raise template.TemplateSyntaxError('"container" template tag provided without arguments (at least one required)')
-register.tag('container', do_container)
\ No newline at end of file
+               raise template.TemplateSyntaxError('"%s" template tag provided without arguments (at least one required)' % tag)
+
+
+register.tag('container', do_container)
+register.tag('blockcontainer', do_container)