From 72fac53a4cd42e6c9f56a581a85f8b47ba61b2ac Mon Sep 17 00:00:00 2001 From: Joseph Spiros Date: Sun, 7 Mar 2010 19:26:14 -0500 Subject: [PATCH] Implementation of a Node class, the subclasses of which respond to requests at different paths. Implemented Redirect and File nodes, and changed the existing Page class to be a subclass of Node as well. So, in addition to Template-based Pages, Philo can now serve plain static files as well as redirects to other locations. Also, removed the requirement on django-mptt, as currently none of its features are needed, and I have yet to figure out how to make it work in multi-table inheritance situations. --- README | 1 - admin.py | 2 ++ models.py | 60 ++++++++++++++++++++++++++++++++++++++++++++++++------- urls.py | 6 +++--- views.py | 15 +++++++------- 5 files changed, 66 insertions(+), 18 deletions(-) diff --git a/README b/README index 81a59cd..82333d6 100644 --- a/README +++ b/README @@ -4,7 +4,6 @@ Prerequisites: * Python 2.5.4+ * simplejson (Not required with Python 2.6+) * Django 1.1.1+ - * django-mptt 0.2+ * (Optional) django-grappelli 2.0+ To contribute, please visit the project website . diff --git a/admin.py b/admin.py index 229e16d..faf4b71 100644 --- a/admin.py +++ b/admin.py @@ -126,5 +126,7 @@ class PageAdmin(EntityAdmin): admin.site.register(Collection, CollectionAdmin) +admin.site.register(Redirect) +admin.site.register(File) admin.site.register(Page, PageAdmin) admin.site.register(Template, TemplateAdmin) diff --git a/models.py b/models.py index 3a06d0a..4eb50f7 100644 --- a/models.py +++ b/models.py @@ -5,12 +5,11 @@ from django.contrib.contenttypes import generic from django.contrib.contenttypes.models import ContentType from django.db import models from django.contrib.sites.models import Site -import mptt from utils import fattr from django.template import add_to_builtins as register_templatetags from django.template import Template as DjangoTemplate from django.template import TemplateDoesNotExist -from django.template import Context +from django.template import Context, RequestContext from django.core.exceptions import ObjectDoesNotExist try: import json @@ -20,6 +19,8 @@ from UserDict import DictMixin from templatetags.containers import ContainerNode from django.template.loader_tags import ExtendsNode, ConstantIncludeNode, IncludeNode from django.template.loader import get_template +from django.http import HttpResponse, HttpResponseServerError, HttpResponseRedirect +from django.core.servers.basehttp import FileWrapper def _ct_model_name(model): @@ -214,6 +215,50 @@ class TreeEntity(TreeModel, Entity): abstract = True +class Node(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(Node, self).save(force_insert, force_update) + + @property + def instance(self): + return self.instance_type.get_object_for_this_type(id=self.id) + + accepts_subpath = False + + def render_to_response(self, request, path=None, subpath=None): + return HttpResponseServerError() + + +class Redirect(Node): + STATUS_CODES = ( + (302, 'Temporary'), + (301, 'Permanent'), + ) + target = models.URLField() + status_code = models.IntegerField(choices=STATUS_CODES, default=302, verbose_name="redirect type") + + def render_to_response(self, request, path=None, subpath=None): + response = HttpResponseRedirect(self.target) + response.status_code = self.status_code + return response + + +class File(Node): + """ For storing arbitrary files """ + 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): + wrapper = FileWrapper(self.file) + response = HttpResponse(wrapper, content_type=self.mimetype) + response['Content-Length'] = self.file.size + return response + + class Template(TreeModel): name = models.CharField(max_length=255) documentation = models.TextField(null=True, blank=True) @@ -274,20 +319,21 @@ class Template(TreeModel): except Template.DoesNotExist: raise TemplateDoesNotExist(template_name) return (template.code, template.origin) -mptt.register(Template) -class Page(TreeEntity): +class Page(Node): template = models.ForeignKey(Template, related_name='pages') title = models.CharField(max_length=255) + def render_to_response(self, request, path=None, subpath=None): + return HttpResponse(self.template.django_template.render(RequestContext(request, {'page': self})), mimetype=self.template.mimetype) + def __unicode__(self): return self.get_path(u' › ', 'title') -mptt.register(Page) -# the following line enables the selection of a page as the root for a given django.contrib.sites Site object -models.ForeignKey(Page, related_name='sites', null=True, blank=True).contribute_to_class(Site, 'root_page') +# the following line enables the selection of a node as the root for a given django.contrib.sites Site object +models.ForeignKey(Node, related_name='sites', null=True, blank=True).contribute_to_class(Site, 'root_node') class Contentlet(models.Model): diff --git a/urls.py b/urls.py index 77ec968..c4fcb5e 100644 --- a/urls.py +++ b/urls.py @@ -1,8 +1,8 @@ from django.conf.urls.defaults import url, include, patterns, handler404, handler500 -from philo.views import page_view +from philo.views import node_view urlpatterns = patterns('', - url(r'^$', page_view, name='philo-root'), - url(r'^(?P.*)$', page_view, name='philo-page-by-path') + url(r'^$', node_view, name='philo-root'), + url(r'^(?P.*)$', node_view, name='philo-node-by-path') ) diff --git a/views.py b/views.py index 65acb52..5e4b7dd 100644 --- a/views.py +++ b/views.py @@ -1,18 +1,19 @@ from django.http import Http404, HttpResponse from django.template import RequestContext from django.contrib.sites.models import Site -from models import Page +from models import Node -def page_view(request, path=None, **kwargs): - page = None + +def node_view(request, path=None, **kwargs): + node = None if path is None: path = '/' try: current_site = Site.objects.get_current() if current_site: - page = Page.objects.get_with_path(path, root=current_site.root_page) - except Page.DoesNotExist: + node = Node.objects.get_with_path(path, root=current_site.root_node) + except Node.DoesNotExist: raise Http404 - if not page: + if not node: raise Http404 - return HttpResponse(page.template.django_template.render(RequestContext(request, {'page': page})), mimetype=page.template.mimetype) + return node.instance.render_to_response(request, path=path) -- 2.20.1