b279fc7c9ec525adcf5b1ac2668084cbd9686371
[philo.git] / contrib / penfield / embed.py
1 from django.contrib.contenttypes import generic
2 from django.contrib.contenttypes.models import ContentType
3 from django.core.exceptions import ValidationError
4 from django.db import models
5 from django.template import Template, loader, loader_tags
6 import re
7 from philo.contrib.penfield.templatetags.embed import EmbedNode
8
9
10 embed_re = re.compile("{% embed (?P<app_label>\w+)\.(?P<model>\w+) (?P<pk>)\w+ %}")
11
12
13 class TemplateField(models.TextField):
14         def validate(self, value, model_instance):
15                 """For value (a template), make sure that all included templates exist."""
16                 super(TemplateField, self).validate(value, model_instance)
17                 try:
18                         self.validate_template(self.to_template(value))
19                 except Exception, e:
20                         raise ValidationError("Template code invalid. Error was: %s: %s" % (e.__class__.__name__, e))
21         
22         def validate_template(self, template):
23                 for node in template.nodelist:
24                         if isinstance(node, loader_tags.ExtendsNode):
25                                 extended_template = node.get_parent(Context())
26                                 self.validate_template(extended_template)
27                         elif isinstance(node, loader_tags.IncludeNode):
28                                 included_template = loader.get_template(node.template_name.resolve(Context()))
29                                 self.validate_template(extended_template)
30         
31         def to_template(self, value):
32                 return Template(value)
33
34
35 class EmbedField(TemplateField):
36         def validate_template(self, template):
37                 """Check to be sure that the embedded instances and templates all exist."""
38                 for node in template.nodelist:
39                         if isinstance(node, loader_tags.ExtendsNode):
40                                 extended_template = node.get_parent(Context())
41                                 self.validate_template(extended_template)
42                         elif isinstance(node, loader_tags.IncludeNode):
43                                 included_template = loader.get_template(node.template_name.resolve(Context()))
44                                 self.validate_template(extended_template)
45                         elif isinstance(node, EmbedNode):
46                                 if node.template_name is not None:
47                                         embedded_template = loader.get_template(node.template_name)
48                                         self.validate_template(embedded_template)
49                                 elif node.object_pk is not None:
50                                         embedded_instance = node.model.objects.get(pk=node.object_pk)
51         
52         def to_template(self, value):
53                 return Template("{% load embed %}" + value)
54
55
56 class Embed(models.Model):
57         embedder_embed_field = models.CharField(max_length=255)
58         
59         embedder_contenttype = models.ForeignKey(ContentType, related_name="embedder_related")
60         embedder_object_id = models.PositiveIntegerField()
61         embedder = generic.GenericForeignKey("embedder_contenttype", "embedder_object_id")
62         
63         embedded_contenttype = models.ForeignKey(ContentType, related_name="embedded_related")
64         embedded_object_id = models.PositiveIntegerField()
65         embedded = generic.GenericForeignKey("embedded_contenttype", "embedded_object_id")
66         
67         def delete(self):
68                 # Unclear whether this would be called by a cascading deletion.
69                 
70                 super(Embed, self).delete()
71         
72         class Meta:
73                 app_label = 'penfield'
74
75
76 class Test(models.Model):
77         template = TemplateField()
78         embedder = EmbedField()
79         
80         class Meta:
81                 app_label = 'penfield'