Added app_label to Tag. Removed app_label from abstract models, as it would be inheri...
[philo.git] / models / nodes.py
index 78df3d6..9c18e52 100644 (file)
@@ -1,19 +1,30 @@
 from django.db import models
 from django.db import models
+from django.contrib.contenttypes.models import ContentType
+from django.contrib.contenttypes import generic
 from django.contrib.sites.models import Site
 from django.http import HttpResponse, HttpResponseServerError, HttpResponseRedirect
 from django.core.servers.basehttp import FileWrapper
 from django.contrib.sites.models import Site
 from django.http import HttpResponse, HttpResponseServerError, HttpResponseRedirect
 from django.core.servers.basehttp import FileWrapper
-from philo.models.base import InheritableTreeEntity
+from philo.models.base import TreeEntity, Entity, QuerySetMapper
+from philo.utils import ContentTypeSubclassLimiter
 from philo.validators import RedirectValidator
 
 
 from philo.validators import RedirectValidator
 
 
-class Node(InheritableTreeEntity):
-       accepts_subpath = False
+_view_content_type_limiter = ContentTypeSubclassLimiter(None)
+
+
+class Node(TreeEntity):
+       view_content_type = models.ForeignKey(ContentType, related_name='node_view_set', limit_choices_to=_view_content_type_limiter)
+       view_object_id = models.PositiveIntegerField()
+       view = generic.GenericForeignKey('view_content_type', 'view_object_id')
+       
+       @property
+       def accepts_subpath(self):
+               return self.view.accepts_subpath
+       
+       def render_to_response(self, request, path=None, subpath=None, extra_context=None):
+               return self.view.render_to_response(self, request, path, subpath, extra_context)
        
        
-       def render_to_response(self, request, path=None, subpath=None):
-               return HttpResponseServerError()
-               
        class Meta:
        class Meta:
-               unique_together = (('parent', 'slug'),)
                app_label = 'philo'
 
 
                app_label = 'philo'
 
 
@@ -21,12 +32,33 @@ class Node(InheritableTreeEntity):
 models.ForeignKey(Node, related_name='sites', null=True, blank=True).contribute_to_class(Site, 'root_node')
 
 
 models.ForeignKey(Node, related_name='sites', null=True, blank=True).contribute_to_class(Site, 'root_node')
 
 
-class MultiNode(Node):
+class View(Entity):
+       nodes = generic.GenericRelation(Node, content_type_field='view_content_type', object_id_field='view_object_id')
+       
+       accepts_subpath = False
+       
+       def attributes_with_node(self, node):
+               return QuerySetMapper(self.attribute_set, passthrough=node.attributes)
+       
+       def relationships_with_node(self, node):
+               return QuerySetMapper(self.relationship_set, passthrough=node.relationships)
+       
+       def render_to_response(self, node, request, path=None, subpath=None, extra_context=None):
+               raise NotImplementedError('View subclasses must implement render_to_response.')
+       
+       class Meta:
+               abstract = True
+
+
+_view_content_type_limiter.cls = View
+
+
+class MultiView(View):
        accepts_subpath = True
        
        urlpatterns = []
        
        accepts_subpath = True
        
        urlpatterns = []
        
-       def render_to_response(self, request, path=None, subpath=None):
+       def render_to_response(self, node, request, path=None, subpath=None, extra_context=None):
                if not subpath:
                        subpath = ""
                subpath = "/" + subpath
                if not subpath:
                        subpath = ""
                subpath = "/" + subpath
@@ -36,18 +68,17 @@ class MultiNode(Node):
        
        class Meta:
                abstract = True
        
        class Meta:
                abstract = True
-               app_label = 'philo'
 
 
 
 
-class Redirect(Node):
+class Redirect(View):
        STATUS_CODES = (
                (302, 'Temporary'),
                (301, 'Permanent'),
        )
        STATUS_CODES = (
                (302, 'Temporary'),
                (301, 'Permanent'),
        )
-       target = models.CharField(max_length=200,validators=[RedirectValidator()])
+       target = models.CharField(max_length=200, validators=[RedirectValidator()])
        status_code = models.IntegerField(choices=STATUS_CODES, default=302, verbose_name='redirect type')
        
        status_code = models.IntegerField(choices=STATUS_CODES, default=302, verbose_name='redirect type')
        
-       def render_to_response(self, request, path=None, subpath=None):
+       def render_to_response(self, node, request, path=None, subpath=None, extra_context=None):
                response = HttpResponseRedirect(self.target)
                response.status_code = self.status_code
                return response
                response = HttpResponseRedirect(self.target)
                response.status_code = self.status_code
                return response
@@ -56,12 +87,13 @@ class Redirect(Node):
                app_label = 'philo'
 
 
                app_label = 'philo'
 
 
-class File(Node):
+class File(View):
        """ For storing arbitrary files """
        """ For storing arbitrary files """
+       
        mimetype = models.CharField(max_length=255)
        file = models.FileField(upload_to='philo/files/%Y/%m/%d')
        
        mimetype = models.CharField(max_length=255)
        file = models.FileField(upload_to='philo/files/%Y/%m/%d')
        
-       def render_to_response(self, request, path=None, subpath=None):
+       def render_to_response(self, node, request, path=None, subpath=None, extra_context=None):
                wrapper = FileWrapper(self.file)
                response = HttpResponse(wrapper, content_type=self.mimetype)
                response['Content-Length'] = self.file.size
                wrapper = FileWrapper(self.file)
                response = HttpResponse(wrapper, content_type=self.mimetype)
                response['Content-Length'] = self.file.size