From: Stephen Burrows Date: Mon, 29 Nov 2010 17:26:41 +0000 (-0500) Subject: Added {% embed %} syntax for embedding. Switched to actually using the... X-Git-Tag: philo-0.9~25^2~2 X-Git-Url: http://git.ithinksw.org/philo.git/commitdiff_plain/0b461b9482695531611ca2ffca78ac4963e33a63 Added {% embed %} syntax for embedding. Switched to actually using the EmbedNode get_instance and get_template methods for greater flexibility. --- diff --git a/templatetags/embed.py b/templatetags/embed.py index d7a8466..ef2eeb2 100644 --- a/templatetags/embed.py +++ b/templatetags/embed.py @@ -26,7 +26,8 @@ class EmbedContext(object): """To return a template for an embed node, find the node's position in the stack and then progress up the stack until a template-defining node is found """ - embeds = self.embeds[embed.content_type] + ct = embed.get_content_type(context) + embeds = self.embeds[ct] embeds = embeds[:embeds.index(embed)][::-1] for e in embeds: template = e.get_template(context) @@ -46,7 +47,7 @@ class EmbedContext(object): else: embed_context = context_dict[EMBED_CONTEXT_KEY] # We can tell where we are in the list of embeds by which have already been rendered. - embeds = embed_context.embeds[embed.content_type][:len(embed_context.rendered)][::-1] + embeds = embed_context.embeds[ct][:len(embed_context.rendered)][::-1] for e in embeds: template = e.get_template(context) if template: @@ -133,7 +134,7 @@ class ConstantEmbedNode(template.Node): else: self.template = None - def compile_instance(self, object_pk, context=None): + def compile_instance(self, object_pk): self.object_pk = object_pk model = self.content_type.model_class() try: @@ -147,7 +148,7 @@ class ConstantEmbedNode(template.Node): def get_instance(self, context): return self.instance - def compile_template(self, template_name, context=None): + def compile_template(self, template_name): try: return template.loader.get_template(template_name) except template.TemplateDoesNotExist: @@ -159,35 +160,40 @@ class ConstantEmbedNode(template.Node): def get_template(self, context): return self.template + def get_content_type(self, context): + return self.content_type + def check_context(self, context): if EMBED_CONTEXT_KEY not in context.render_context: context.render_context[EMBED_CONTEXT_KEY] = EmbedContext() embed_context = context.render_context[EMBED_CONTEXT_KEY] - - if self.content_type not in embed_context.embeds: - embed_context.embeds[self.content_type] = [self] - elif self not in embed_context.embeds[self.content_type]: - embed_context.embeds[self.content_type].append(self) + ct = self.get_content_type(context) + if ct not in embed_context.embeds: + embed_context.embeds[ct] = [self] + elif self not in embed_context.embeds[ct]: + embed_context.embeds[ct].append(self) - def mark_rendered(self, context): + def mark_rendered_for(self, context): context.render_context[EMBED_CONTEXT_KEY].rendered.append(self) def render(self, context): self.check_context(context) - if self.template is not None: - if self.template is False: + template = self.get_template(context) + if template is not None: + self.mark_rendered_for(context) + if template is False: return settings.TEMPLATE_STRING_IF_INVALID - self.mark_rendered(context) return '' - # Otherwise self.instance should be set. Render the instance with the appropriate template! - if self.instance is None or self.instance is False: - self.mark_rendered(context) + # Otherwise an instance should be available. Render the instance with the appropriate template! + instance = self.get_instance(context) + if instance is None or instance is False: + self.mark_rendered_for(context) return settings.TEMPLATE_STRING_IF_INVALID - return self.render_instance(context, self.instance) + return self.render_instance(context, instance) def render_instance(self, context, instance): try: @@ -205,7 +211,7 @@ class ConstantEmbedNode(template.Node): context.update(kwargs) t_rendered = t.render(context) context.pop() - self.mark_rendered(context) + self.mark_rendered_for(context) return t_rendered @@ -213,11 +219,7 @@ class EmbedNode(ConstantEmbedNode): def __init__(self, content_type, object_pk=None, template_name=None, kwargs=None): assert template_name is not None or object_pk is not None self.content_type = content_type - - kwargs = kwargs or {} - for k, v in kwargs.items(): - kwargs[k] = v - self.kwargs = kwargs + self.kwargs = kwargs or {} if object_pk is not None: self.object_pk = object_pk @@ -232,27 +234,29 @@ class EmbedNode(ConstantEmbedNode): self.template = None def get_instance(self, context): - return self.compile_instance(self.object_pk, context) + if self.object_pk is None: + return None + return self.compile_instance(self.object_pk.resolve(context)) def get_template(self, context): - return self.compile_template(self.template_name, context) + if self.template_name is None: + return None + return self.compile_template(self.template_name.resolve(context)) + + +class InstanceEmbedNode(EmbedNode): + def __init__(self, instance, kwargs=None): + self.instance = instance + self.kwargs = kwargs or {} - def render(self, context): - self.check_context(context) - - if self.template_name is not None: - self.mark_rendered(context) - return '' - - if self.object_pk is None: - if settings.TEMPLATE_DEBUG: - raise ValueError("NoneType is not a valid object_pk value") - self.mark_rendered(context) - return settings.TEMPLATE_STRING_IF_INVALID - - instance = self.compile_instance(self.object_pk.resolve(context)) - - return self.render_instance(context, instance) + def get_template(self, context): + return None + + def get_instance(self, context): + return self.instance.resolve(context) + + def get_content_type(self, context): + return ContentType.objects.get_for_model(self.get_instance(context)) def get_embedded(self): @@ -262,51 +266,63 @@ def get_embedded(self): setattr(ConstantEmbedNode, LOADED_TEMPLATE_ATTR, property(get_embedded)) +def get_content_type(bit): + try: + app_label, model = bit.split('.') + except ValueError: + raise template.TemplateSyntaxError('"%s" template tag expects the first argument to be of the form app_label.model' % tag) + try: + ct = ContentType.objects.get(app_label=app_label, model=model) + except ContentType.DoesNotExist: + raise template.TemplateSyntaxError('"%s" template tag requires an argument of the form app_label.model which refers to an installed content type (see django.contrib.contenttypes)' % tag) + return ct + + def do_embed(parser, token): """ The {% embed %} tag can be used in two ways: {% embed . with