+++ /dev/null
-from django.contrib import admin
-from django.contrib.contenttypes import generic
-from django.contrib.contenttypes.models import ContentType
-from django import forms
-from django.conf import settings
-from django.utils.translation import ugettext as _
-from django.utils.safestring import mark_safe
-from django.utils.html import escape
-from django.utils.text import truncate_words
-from philo.models import *
-from django.core.exceptions import ValidationError, ObjectDoesNotExist
-from validators import TreeParentValidator, TreePositionValidator
-
-
-COLLAPSE_CLASSES = ('collapse', 'collapse-closed', 'closed',)
-
-
-class AttributeInline(generic.GenericTabularInline):
- ct_field = 'entity_content_type'
- ct_fk_field = 'entity_object_id'
- model = Attribute
- extra = 1
- template = 'admin/philo/edit_inline/tabular_collapse.html'
- allow_add = True
-
-
-class RelationshipInline(generic.GenericTabularInline):
- ct_field = 'entity_content_type'
- ct_fk_field = 'entity_object_id'
- model = Relationship
- extra = 1
- template = 'admin/philo/edit_inline/tabular_collapse.html'
- allow_add = True
-
-
-class EntityAdmin(admin.ModelAdmin):
- inlines = [AttributeInline, RelationshipInline]
- save_on_top = True
-
-
-class CollectionMemberInline(admin.TabularInline):
- fk_name = 'collection'
- model = CollectionMember
- extra = 1
- classes = COLLAPSE_CLASSES
- allow_add = True
- fields = ('member_content_type', 'member_object_id', 'index',)
-
-
-class CollectionAdmin(admin.ModelAdmin):
- inlines = [CollectionMemberInline]
- list_display = ('name', 'description', 'get_count')
-
-
-class NodeAdmin(EntityAdmin):
- pass
-
-
-class ModelLookupWidget(forms.TextInput):
- # is_hidden = False
-
- def __init__(self, content_type, attrs=None):
- self.content_type = content_type
- super(ModelLookupWidget, self).__init__(attrs)
-
- def render(self, name, value, attrs=None):
- related_url = '../../../%s/%s/' % (self.content_type.app_label, self.content_type.model)
- if attrs is None:
- attrs = {}
- if not attrs.has_key('class'):
- attrs['class'] = 'vForeignKeyRawIdAdminField'
- output = super(ModelLookupWidget, self).render(name, value, attrs)
- output += '<a href="%s" class="related-lookup" id="lookup_id_%s" onclick="return showRelatedObjectLookupPopup(this);">' % (related_url, name)
- output += '<img src="%simg/admin/selector-search.gif" width="16" height="16" alt="%s" />' % (settings.ADMIN_MEDIA_PREFIX, _('Lookup'))
- output += '</a>'
- if value:
- value_class = self.content_type.model_class()
- try:
- value_object = value_class.objects.get(pk=value)
- output += ' <strong>%s</strong>' % escape(truncate_words(value_object, 14))
- except value_class.DoesNotExist:
- pass
- return mark_safe(output)
-
-
-class TreeForm(forms.ModelForm):
- def __init__(self, *args, **kwargs):
- super(TreeForm, self).__init__(*args, **kwargs)
- instance = self.instance
- instance_class = self.get_instance_class()
-
- if instance_class is not None:
- try:
- self.fields['parent'].queryset = instance_class.objects.exclude(id=instance.id)
- except ObjectDoesNotExist:
- pass
-
- self.fields['parent'].validators = [TreeParentValidator(*self.get_validator_args())]
-
- def get_instance_class(self):
- return self.instance.__class__
-
- def get_validator_args(self):
- return [self.instance]
-
- def clean(self):
- cleaned_data = self.cleaned_data
-
- try:
- parent = cleaned_data['parent']
- slug = cleaned_data['slug']
- obj_class = self.get_instance_class()
- tpv = TreePositionValidator(parent, slug, obj_class)
- tpv(self.instance)
- except KeyError:
- pass
-
- return cleaned_data
-
-
-class NodeForm(TreeForm):
- def get_instance_class(self):
- return Node
-
- def get_validator_args(self):
- return [self.instance, 'instance']
-
-
-class PageAdminForm(NodeForm):
- class Meta:
- model = Page
-
-
-class RedirectAdminForm(NodeForm):
- class Meta:
- model = Redirect
-
-
-class FileAdminForm(NodeForm):
- class Meta:
- model = File
-
-
-class RedirectAdmin(NodeAdmin):
- fieldsets = (
- (None, {
- 'fields': ('slug', 'target', 'status_code')
- }),
- ('URL/Tree/Hierarchy', {
- 'classes': COLLAPSE_CLASSES,
- 'fields': ('parent',)
- }),
- )
- list_display=('slug', 'target', 'path', 'status_code',)
- list_filter=('status_code',)
- form = RedirectAdminForm
-
-
-class FileAdmin(NodeAdmin):
- prepopulated_fields = {'slug': ('file',)}
- fieldsets = (
- (None, {
- 'fields': ('file', 'slug', 'mimetype')
- }),
- ('URL/Tree/Hierarchy', {
- 'classes': COLLAPSE_CLASSES,
- 'fields': ('parent',)
- }),
- )
- form=FileAdminForm
- list_display=('slug', 'mimetype', 'path', 'file',)
-
-
-class PageAdmin(NodeAdmin):
- add_form_template = 'admin/philo/page/add_form.html'
- prepopulated_fields = {'slug': ('title',)}
- fieldsets = (
- (None, {
- 'fields': ('title', 'slug', 'template')
- }),
- ('URL/Tree/Hierarchy', {
- 'classes': COLLAPSE_CLASSES,
- 'fields': ('parent',)
- }),
- )
- list_display = ('title', 'path', 'template')
- list_filter = ('template',)
- search_fields = ['title', 'slug', 'contentlets__content']
- form = PageAdminForm
-
- def get_fieldsets(self, request, obj=None, **kwargs):
- fieldsets = list(self.fieldsets)
- if obj: # if no obj, creating a new page, thus no template set, thus no containers
- template = obj.template
- if template.documentation:
- fieldsets.append(('Template Documentation', {
- 'description': template.documentation
- }))
- contentlet_containers, contentreference_containers = template.containers
- for container_name in contentlet_containers:
- fieldsets.append((('Container: %s' % container_name), {
- 'fields': (('contentlet_container_content_%s' % container_name), ('contentlet_container_dynamic_%s' % container_name))
- }))
- for container_name, container_content_type in contentreference_containers:
- fieldsets.append((('Container: %s' % container_name), {
- 'fields': (('contentreference_container_%s' % container_name),)
- }))
- return fieldsets
-
- def get_form(self, request, obj=None, **kwargs):
- form = super(PageAdmin, self).get_form(request, obj, **kwargs)
- if obj: # if no obj, creating a new page, thus no template set, thus no containers
- page = obj
- template = page.template
- contentlet_containers, contentreference_containers = template.containers
- for container_name in contentlet_containers:
- initial_content = None
- initial_dynamic = False
- try:
- contentlet = page.contentlets.get(name__exact=container_name)
- initial_content = contentlet.content
- initial_dynamic = contentlet.dynamic
- except Contentlet.DoesNotExist:
- pass
- form.base_fields[('contentlet_container_content_%s' % container_name)] = forms.CharField(label='Content', widget=forms.Textarea(), initial=initial_content, required=False)
- form.base_fields[('contentlet_container_dynamic_%s' % container_name)] = forms.BooleanField(label='Dynamic', help_text='Specify whether this content contains dynamic template code', initial=initial_dynamic, required=False)
- for container_name, container_content_type in contentreference_containers:
- initial_content = None
- try:
- initial_content = page.contentreferences.get(name__exact=container_name, content_type=container_content_type).content.pk
- except (ContentReference.DoesNotExist, AttributeError):
- pass
- form.base_fields[('contentreference_container_%s' % container_name)] = forms.ModelChoiceField(label='References', widget=ModelLookupWidget(container_content_type), initial=initial_content, required=False, queryset=container_content_type.model_class().objects.all())
- return form
-
- def save_model(self, request, page, form, change):
- page.save()
- template = page.template
- contentlet_containers, contentreference_containers = template.containers
- for container_name in contentlet_containers:
- if (('contentlet_container_content_%s' % container_name) in form.cleaned_data) and (('contentlet_container_dynamic_%s' % container_name) in form.cleaned_data):
- content = form.cleaned_data[('contentlet_container_content_%s' % container_name)]
- dynamic = form.cleaned_data[('contentlet_container_dynamic_%s' % container_name)]
- contentlet, created = page.contentlets.get_or_create(name=container_name, defaults={'content': content, 'dynamic': dynamic})
- if not created:
- contentlet.content = content
- contentlet.dynamic = dynamic
- contentlet.save()
- for container_name, container_content_type in contentreference_containers:
- if ('contentreference_container_%s' % container_name) in form.cleaned_data:
- content = form.cleaned_data[('contentreference_container_%s' % container_name)]
- try:
- contentreference = page.contentreferences.get(name=container_name)
- except ContentReference.DoesNotExist:
- contentreference = ContentReference(name=container_name, page=page, content_type=container_content_type)
-
- if content == None:
- contentreference.content_id = None
- else:
- contentreference.content_id = content.id
-
- contentreference.save()
-
-
-class TemplateAdmin(admin.ModelAdmin):
- prepopulated_fields = {'slug': ('name',)}
- fieldsets = (
- (None, {
- 'fields': ('parent', 'name', 'slug')
- }),
- ('Documentation', {
- 'classes': COLLAPSE_CLASSES,
- 'fields': ('documentation',)
- }),
- (None, {
- 'fields': ('code',)
- }),
- ('Advanced', {
- 'classes': COLLAPSE_CLASSES,
- 'fields': ('mimetype',)
- }),
- )
- save_on_top = True
- save_as = True
- list_display = ('__unicode__', 'slug', 'get_path',)
- form = TreeForm
-
-
-admin.site.register(Collection, CollectionAdmin)
-admin.site.register(Redirect, RedirectAdmin)
-admin.site.register(File, FileAdmin)
-admin.site.register(Page, PageAdmin)
-admin.site.register(Template, TemplateAdmin)
--- /dev/null
+from philo.admin.base import *
+from philo.admin.collections import *
+from philo.admin.nodes import *
+from philo.admin.pages import *
\ No newline at end of file
--- /dev/null
+from django.contrib import admin
+#from django.contrib.contenttypes.models import ContentType
+from django.contrib.contenttypes import generic
+#from django import forms
+#from django.conf import settings
+#from django.utils.translation import ugettext as _
+#from django.utils.safestring import mark_safe
+#from django.utils.html import escape
+#from django.utils.text import truncate_words
+from philo.models import *
+#from philo.admin import widgets
+#from django.core.exceptions import ValidationError, ObjectDoesNotExist
+#from validators import TreeParentValidator, TreePositionValidator
+
+
+COLLAPSE_CLASSES = ('collapse', 'collapse-closed', 'closed',)
+
+
+class AttributeInline(generic.GenericTabularInline):
+ ct_field = 'entity_content_type'
+ ct_fk_field = 'entity_object_id'
+ model = Attribute
+ extra = 1
+ template = 'admin/philo/edit_inline/tabular_collapse.html'
+ allow_add = True
+
+
+class RelationshipInline(generic.GenericTabularInline):
+ ct_field = 'entity_content_type'
+ ct_fk_field = 'entity_object_id'
+ model = Relationship
+ extra = 1
+ template = 'admin/philo/edit_inline/tabular_collapse.html'
+ allow_add = True
+
+
+class EntityAdmin(admin.ModelAdmin):
+ inlines = [AttributeInline, RelationshipInline]
+ save_on_top = True
\ No newline at end of file
--- /dev/null
+from django.contrib import admin
+from philo.admin.base import COLLAPSE_CLASSES
+from philo.models import CollectionMember, Collection
+
+
+class CollectionMemberInline(admin.TabularInline):
+ fk_name = 'collection'
+ model = CollectionMember
+ extra = 1
+ classes = COLLAPSE_CLASSES
+ allow_add = True
+ fields = ('member_content_type', 'member_object_id', 'index')
+
+
+class CollectionAdmin(admin.ModelAdmin):
+ inlines = [CollectionMemberInline]
+ list_display = ('name', 'description', 'get_count')
+
+
+admin.site.register(Collection, CollectionAdmin)
\ No newline at end of file
--- /dev/null
+from django.contrib import admin
+from philo.admin.base import EntityAdmin
+from philo.models import Node, Redirect, File
+
+
+class NodeAdmin(EntityAdmin):
+ pass
+
+
+class ViewAdmin(EntityAdmin):
+ pass
+
+
+class RedirectAdmin(ViewAdmin):
+ fieldsets = (
+ (None, {
+ 'fields': ('target', 'status_code')
+ }),
+ )
+ list_display = ('target', 'status_code')
+ list_filter = ('status_code',)
+
+
+class FileAdmin(ViewAdmin):
+ fieldsets = (
+ (None, {
+ 'fields': ('file', 'mimetype')
+ }),
+ )
+ list_display = ('mimetype', 'file')
+
+
+admin.site.register(Node, NodeAdmin)
+admin.site.register(Redirect, RedirectAdmin)
+admin.site.register(File, FileAdmin)
\ No newline at end of file
--- /dev/null
+from django.contrib import admin
+from django import forms
+from philo.admin import widgets
+from philo.admin.base import COLLAPSE_CLASSES
+from philo.admin.nodes import ViewAdmin
+from philo.models.pages import Page, Template, Contentlet, ContentReference
+
+
+class PageAdmin(ViewAdmin):
+ add_form_template = 'admin/philo/page/add_form.html'
+ fieldsets = (
+ (None, {
+ 'fields': ('title', 'template')
+ }),
+ )
+ list_display = ('title', 'template')
+ list_filter = ('template',)
+ search_fields = ['title', 'contentlets__content']
+
+ def get_fieldsets(self, request, obj=None, **kwargs):
+ fieldsets = list(self.fieldsets)
+ if obj: # if no obj, creating a new page, thus no template set, thus no containers
+ template = obj.template
+ if template.documentation:
+ fieldsets.append(('Template Documentation', {
+ 'description': template.documentation
+ }))
+ contentlet_containers, contentreference_containers = template.containers
+ for container_name in contentlet_containers:
+ fieldsets.append((('Container: %s' % container_name), {
+ 'fields': (('contentlet_container_content_%s' % container_name), ('contentlet_container_dynamic_%s' % container_name))
+ }))
+ for container_name, container_content_type in contentreference_containers:
+ fieldsets.append((('Container: %s' % container_name), {
+ 'fields': (('contentreference_container_%s' % container_name),)
+ }))
+ return fieldsets
+
+ def get_form(self, request, obj=None, **kwargs):
+ form = super(PageAdmin, self).get_form(request, obj, **kwargs)
+ if obj: # if no obj, creating a new page, thus no template set, thus no containers
+ page = obj
+ template = page.template
+ contentlet_containers, contentreference_containers = template.containers
+ for container_name in contentlet_containers:
+ initial_content = None
+ initial_dynamic = False
+ try:
+ contentlet = page.contentlets.get(name__exact=container_name)
+ initial_content = contentlet.content
+ initial_dynamic = contentlet.dynamic
+ except Contentlet.DoesNotExist:
+ pass
+ form.base_fields[('contentlet_container_content_%s' % container_name)] = forms.CharField(label='Content', widget=forms.Textarea(), initial=initial_content, required=False)
+ form.base_fields[('contentlet_container_dynamic_%s' % container_name)] = forms.BooleanField(label='Dynamic', help_text='Specify whether this content contains dynamic template code', initial=initial_dynamic, required=False)
+ for container_name, container_content_type in contentreference_containers:
+ initial_content = None
+ try:
+ initial_content = page.contentreferences.get(name__exact=container_name, content_type=container_content_type).content.pk
+ except (ContentReference.DoesNotExist, AttributeError):
+ pass
+ form.base_fields[('contentreference_container_%s' % container_name)] = forms.ModelChoiceField(label='References', widget=widgets.ModelLookupWidget(container_content_type), initial=initial_content, required=False, queryset=container_content_type.model_class().objects.all())
+ return form
+
+ def save_model(self, request, page, form, change):
+ page.save()
+ template = page.template
+ contentlet_containers, contentreference_containers = template.containers
+ for container_name in contentlet_containers:
+ if (('contentlet_container_content_%s' % container_name) in form.cleaned_data) and (('contentlet_container_dynamic_%s' % container_name) in form.cleaned_data):
+ content = form.cleaned_data[('contentlet_container_content_%s' % container_name)]
+ dynamic = form.cleaned_data[('contentlet_container_dynamic_%s' % container_name)]
+ contentlet, created = page.contentlets.get_or_create(name=container_name, defaults={'content': content, 'dynamic': dynamic})
+ if not created:
+ contentlet.content = content
+ contentlet.dynamic = dynamic
+ contentlet.save()
+ for container_name, container_content_type in contentreference_containers:
+ if ('contentreference_container_%s' % container_name) in form.cleaned_data:
+ content = form.cleaned_data[('contentreference_container_%s' % container_name)]
+ try:
+ contentreference = page.contentreferences.get(name=container_name)
+ except ContentReference.DoesNotExist:
+ contentreference = ContentReference(name=container_name, page=page, content_type=container_content_type)
+
+ if content == None:
+ contentreference.content_id = None
+ else:
+ contentreference.content_id = content.id
+
+ contentreference.save()
+
+
+class TemplateAdmin(admin.ModelAdmin):
+ prepopulated_fields = {'slug': ('name',)}
+ fieldsets = (
+ (None, {
+ 'fields': ('parent', 'name', 'slug')
+ }),
+ ('Documentation', {
+ 'classes': COLLAPSE_CLASSES,
+ 'fields': ('documentation',)
+ }),
+ (None, {
+ 'fields': ('code',)
+ }),
+ ('Advanced', {
+ 'classes': COLLAPSE_CLASSES,
+ 'fields': ('mimetype',)
+ }),
+ )
+ save_on_top = True
+ save_as = True
+ list_display = ('__unicode__', 'slug', 'get_path',)
+
+
+admin.site.register(Page, PageAdmin)
+admin.site.register(Template, TemplateAdmin)
\ No newline at end of file
--- /dev/null
+from django import forms
+from django.conf import settings
+
+
+class ModelLookupWidget(forms.TextInput):
+ # is_hidden = False
+
+ def __init__(self, content_type, attrs=None):
+ self.content_type = content_type
+ super(ModelLookupWidget, self).__init__(attrs)
+
+ def render(self, name, value, attrs=None):
+ related_url = '../../../%s/%s/' % (self.content_type.app_label, self.content_type.model)
+ if attrs is None:
+ attrs = {}
+ if not attrs.has_key('class'):
+ attrs['class'] = 'vForeignKeyRawIdAdminField'
+ output = super(ModelLookupWidget, self).render(name, value, attrs)
+ output += '<a href="%s" class="related-lookup" id="lookup_id_%s" onclick="return showRelatedObjectLookupPopup(this);">' % (related_url, name)
+ output += '<img src="%simg/admin/selector-search.gif" width="16" height="16" alt="%s" />' % (settings.ADMIN_MEDIA_PREFIX, _('Lookup'))
+ output += '</a>'
+ if value:
+ value_class = self.content_type.model_class()
+ try:
+ value_object = value_class.objects.get(pk=value)
+ output += ' <strong>%s</strong>' % escape(truncate_words(value_object, 14))
+ except value_class.DoesNotExist:
+ pass
+ return mark_safe(output)
\ No newline at end of file
from django.contrib.contenttypes import generic
from django.utils import simplejson as json
from django.core.exceptions import ObjectDoesNotExist
+from philo.utils import ContentTypeRegistryLimiter
from UserDict import DictMixin
-def register_value_model(model):
- pass
-
-
-def unregister_value_model(model):
- pass
-
-
class Attribute(models.Model):
entity_content_type = models.ForeignKey(ContentType, verbose_name='Entity type')
entity_object_id = models.PositiveIntegerField(verbose_name='Entity ID')
app_label = 'philo'
+value_content_type_limiter = ContentTypeRegistryLimiter()
+
+
+def register_value_model(model):
+ value_content_type_limiter.register_class(model)
+
+
+def unregister_value_model(model):
+ value_content_type_limiter.unregister_class(model)
+
+
+
class Relationship(models.Model):
entity_content_type = models.ForeignKey(ContentType, related_name='relationship_entity_set', verbose_name='Entity type')
entity_object_id = models.PositiveIntegerField(verbose_name='Entity ID')
entity = generic.GenericForeignKey('entity_content_type', 'entity_object_id')
key = models.CharField(max_length=255)
- value_content_type = models.ForeignKey(ContentType, related_name='relationship_value_set', verbose_name='Value type')
+ value_content_type = models.ForeignKey(ContentType, related_name='relationship_value_set', limit_choices_to=value_content_type_limiter, verbose_name='Value type')
value_object_id = models.PositiveIntegerField(verbose_name='Value ID')
value = generic.GenericForeignKey('value_content_type', 'value_object_id')
return self.path
class Meta:
+ unique_together = (('parent', 'slug'),)
abstract = True
app_label = 'philo'
return QuerySetMapper(self.relationship_set, passthrough=self.parent.relationships)
return super(TreeEntity, self).relationships
- class Meta:
- abstract = True
- app_label = 'philo'
-
-
-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):
- try:
- return self.instance_type.get_object_for_this_type(id=self.id)
- except:
- return None
-
- def get_path(self, pathsep='/', field='slug'):
- path = getattr(self.instance, field, getattr(self.instance, 'slug', '?'))
- parent = self.parent
- while parent:
- path = getattr(parent.instance, field, getattr(parent.instance, 'slug', '?')) + pathsep + path
- parent = parent.parent
- return path
- path = property(get_path)
-
- @property
- 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
app_label = 'philo'
\ No newline at end of file
from django.db import models
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic
-from philo.models.base import register_value_model
+from philo.models.base import value_content_type_limiter, register_value_model
from philo.utils import fattr
objects = CollectionMemberManager()
collection = models.ForeignKey(Collection, related_name='members')
index = models.PositiveIntegerField(verbose_name='Index', help_text='This will determine the ordering of the item within the collection. (Optional)', null=True, blank=True)
- member_content_type = models.ForeignKey(ContentType, verbose_name='Member type')
+ member_content_type = models.ForeignKey(ContentType, limit_choices_to=value_content_type_limiter, verbose_name='Member type')
member_object_id = models.PositiveIntegerField(verbose_name='Member ID')
member = generic.GenericForeignKey('member_content_type', 'member_object_id')
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 philo.models.base import InheritableTreeEntity
+from philo.models.base import TreeEntity, Entity
+from philo.utils import ContentTypeSubclassLimiter
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):
- return HttpResponseServerError()
-
+ return self.view.render_to_response(self, request, path, subpath)
+
class Meta:
- unique_together = (('parent', 'slug'),)
app_label = 'philo'
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 render_to_response(self, node, request, path=None, subpath=None):
+ raise NotImplementedError('View subclasses must implement render_to_response.')
+
+ class Meta:
+ abstract = True
+ app_label = 'philo'
+
+
+_view_content_type_limiter.cls = View
+
+
+class MultiView(View):
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):
if not subpath:
subpath = ""
subpath = "/" + subpath
app_label = 'philo'
-class Redirect(Node):
+class Redirect(View):
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')
- def render_to_response(self, request, path=None, subpath=None):
+ def render_to_response(self, node, request, path=None, subpath=None):
response = HttpResponseRedirect(self.target)
response.status_code = self.status_code
return response
app_label = 'philo'
-class File(Node):
+class File(View):
""" 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):
+ def render_to_response(self, node, request, path=None, subpath=None):
wrapper = FileWrapper(self.file)
response = HttpResponse(wrapper, content_type=self.mimetype)
response['Content-Length'] = self.file.size
from django.template.loader_tags import ExtendsNode, ConstantIncludeNode, IncludeNode
from django.http import HttpResponse
from philo.models.base import TreeModel, register_value_model
-from philo.models.nodes import Node
+from philo.models.nodes import View
from philo.utils import fattr
from philo.templatetags.containers import ContainerNode
app_label = 'philo'
-class Page(Node):
+class Page(View):
"""
Represents a page - something which is rendered according to a template. 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)
- def render_to_response(self, request, path=None, subpath=None):
+ def render_to_response(self, node, 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')
+ return self.title
class Meta:
app_label = 'philo'
except:
pass
return settings.TEMPLATE_STRING_IF_INVALID
-
-
+
+
def do_membersof(parser, token):
"""
{% membersof <collection> with <model> as <var> %}
-from django.conf.urls.defaults import url, include, patterns, handler404, handler500
+from django.conf.urls.defaults import patterns, url
from philo.views import node_view
+from django.db import models
+from django.contrib.contenttypes.models import ContentType
+
+
+class ContentTypeLimiter(object):
+ def q_object(self):
+ return models.Q(pk__in=[])
+
+ def add_to_query(self, query, *args, **kwargs):
+ query.add_q(self.q_object(), *args, **kwargs)
+
+
+class ContentTypeRegistryLimiter(ContentTypeLimiter):
+ def __init__(self):
+ self.classes = []
+
+ def register_class(self, cls):
+ self.classes.append(cls)
+
+ def unregister_class(self, cls):
+ self.classes.remove(cls)
+
+ def q_object(self):
+ contenttype_pks = []
+ for cls in self.classes:
+ try:
+ if issubclass(cls, models.Model):
+ if not cls._meta.abstract:
+ contenttype = ContentType.objects.get_for_model(cls)
+ contenttype_pks.append(contenttype.pk)
+ except:
+ pass
+ return models.Q(pk__in=contenttype_pks)
+
+
+class ContentTypeSubclassLimiter(ContentTypeLimiter):
+ def __init__(self, cls, inclusive=False):
+ self.cls = cls
+ self.inclusive = inclusive
+
+ def q_object(self):
+ contenttype_pks = []
+ for subclass in self.cls.__subclasses__():
+ try:
+ if issubclass(subclass, models.Model):
+ if not subclass._meta.abstract:
+ if not self.inclusive and subclass is self.cls:
+ continue
+ contenttype = ContentType.objects.get_for_model(subclass)
+ contenttype_pks.append(contenttype.pk)
+ except:
+ pass
+ return models.Q(pk__in=contenttype_pks)
+
+
def fattr(*args, **kwargs):
def wrapper(function):
for key in kwargs:
-from django.core.exceptions import ValidationError
from django.utils.translation import ugettext_lazy as _
from django.core.validators import RegexValidator
import re
-class TreeParentValidator(object):
- """
- constructor takes instance and parent_attr, where instance is the model
- being validated and parent_attr is where to look on that parent for the
- comparison.
- """
- #message = _("A tree element can't be its own parent.")
- code = 'invalid'
-
- def __init__(self, instance, parent_attr=None, message=None, code=None):
- self.instance = instance
- self.parent_attr = parent_attr
- self.static_message = message
- if code is not None:
- self.code = code
-
- def __call__(self, value):
- """
- Validates that the self.instance is not found in the parent tree of
- the node given as value.
- """
- parent = value
-
- while parent:
- comparison=self.get_comparison(parent)
- if comparison == self.instance:
- # using (self.message, code=self.code) results in the admin interface
- # screwing with the error message and making it be 'Enter a valid value'
- raise ValidationError(self.message)
- parent=parent.parent
-
- def get_comparison(self, parent):
- if self.parent_attr and hasattr(parent, self.parent_attr):
- return getattr(parent, self.parent_attr)
-
- return parent
-
- def get_message(self):
- return self.static_message or _(u"A %s can't be its own parent." % self.instance.__class__.__name__)
- message = property(get_message)
-
-
-class TreePositionValidator(object):
- code = 'invalid'
-
- def __init__(self, parent, slug, obj_class, message=None, code=None):
- self.parent = parent
- self.slug = slug
- self.obj_class = obj_class
- self.static_message = message
-
- if code is not None:
- self.code = code
-
- def __call__(self, value):
- """
- Validates that there is no obj of obj_class with the same position
- as the compared obj (value) but a different id.
- """
- if not isinstance(value, self.obj_class):
- raise ValidationError(_(u"The value must be an instance of %s." % self.obj_class.__name__))
-
- try:
- obj = self.obj_class.objects.get(slug=self.slug, parent=self.parent)
-
- if obj.id != value.id:
- raise ValidationError(self.message)
-
- except self.obj_class.DoesNotExist:
- pass
-
- def get_message(self):
- return self.static_message or _(u"A %s with that path (parent and slug) already exists." % self.obj_class.__name__)
- message = property(get_message)
-
-
class RedirectValidator(RegexValidator):
"""Based loosely on the URLValidator, but no option to verify_exists"""
regex = re.compile(
raise Http404
if not node:
raise Http404
- if subpath and not node.instance.accepts_subpath:
+ if subpath and not node.accepts_subpath:
raise Http404
- return node.instance.render_to_response(request, path=path, subpath=subpath)
+ return node.render_to_response(request, path=path, subpath=subpath)