Merge branch '1.1'

This commit is contained in:
Corey Oordt 2012-07-12 19:32:10 -04:00
commit 213a208a23
53 changed files with 1477 additions and 945 deletions

View file

@ -1,7 +1,24 @@
=================
Django Categories
=================
Django Categories grew out of our need to provide a basic hierarchical taxonomy management system that multiple applications could use independently or in concert.
As a news site, our stories, photos, and other content get divided into "sections" and we wanted all the apps to use the same set of sections. As our needs grew, the Django Categories grew in the functionality it gave to category handling within web pages.
New in 1.1
==========
* Fixed a cosmetic bug in the Django 1.4 admin. Action checkboxes now only appear once.
* Template tags are refactored to allow easy use of any model derived from ``CategoryBase``.
* Improved test suite.
* Improved some of the documentation.
Upgrade path from 1.0.2 to 1.0.3
================================

View file

@ -1,11 +1,12 @@
__version_info__ = {
'major': 1,
'minor': 0,
'micro': 5,
'minor': 1,
'micro': 0,
'releaselevel': 'final',
'serial': 1
}
def get_version(short=False):
assert __version_info__['releaselevel'] in ('alpha', 'beta', 'final')
vers = ["%(major)i.%(minor)i" % __version_info__, ]

View file

@ -32,7 +32,7 @@ if RELATION_MODELS:
class CategoryAdminForm(CategoryBaseAdminForm):
class Meta:
model = Category
def clean_alternate_title(self):
if self.instance is None or not self.cleaned_data['alternate_title']:
return self.cleaned_data['name']
@ -48,7 +48,7 @@ class CategoryAdmin(CategoryBaseAdmin):
'fields': ('parent', 'name', 'thumbnail', 'active')
}),
('Meta Data', {
'fields': ('alternate_title', 'alternate_url', 'description',
'fields': ('alternate_title', 'alternate_url', 'description',
'meta_keywords', 'meta_extra'),
'classes': ('collapse',),
}),
@ -57,10 +57,10 @@ class CategoryAdmin(CategoryBaseAdmin):
'classes': ('collapse',),
}),
)
if RELATION_MODELS:
inlines = [InlineCategoryRelation,]
inlines = [InlineCategoryRelation, ]
class Media:
js = (JAVASCRIPT_URL + 'genericcollections.js',)

View file

@ -16,6 +16,7 @@ from mptt.managers import TreeManager
from .editor.tree_editor import TreeEditor
from .settings import ALLOW_SLUG_CHANGE, SLUG_TRANSLITERATOR
class CategoryManager(models.Manager):
"""
A manager that adds an "active()" method for all active categories
@ -32,44 +33,44 @@ class CategoryBase(MPTTModel):
This base model includes the absolute bare bones fields and methods. One
could simply subclass this model and do nothing else and it should work.
"""
parent = TreeForeignKey('self',
blank=True,
null=True,
related_name="children",
parent = TreeForeignKey('self',
blank=True,
null=True,
related_name="children",
verbose_name='Parent')
name = models.CharField(max_length=100)
slug = models.SlugField()
active = models.BooleanField(default=True)
objects = CategoryManager()
tree = TreeManager()
def save(self, *args, **kwargs):
"""
While you can activate an item without activating its descendants,
It doesn't make sense that you can deactivate an item and have its
It doesn't make sense that you can deactivate an item and have its
decendants remain active.
"""
if not self.slug:
self.slug = slugify(SLUG_TRANSLITERATOR(self.name))[:50]
super(CategoryBase, self).save(*args, **kwargs)
if not self.active:
for item in self.get_descendants():
if item.active != self.active:
item.active = self.active
item.save()
def __unicode__(self):
ancestors = self.get_ancestors()
return ' > '.join([force_unicode(i.name) for i in ancestors]+[self.name,])
return ' > '.join([force_unicode(i.name) for i in ancestors] + [self.name, ])
class Meta:
abstract = True
unique_together = ('parent', 'name')
ordering = ('tree_id', 'lft')
class MPTTMeta:
order_insertion_by = 'name'
@ -79,11 +80,11 @@ class CategoryBaseAdminForm(forms.ModelForm):
if self.instance is None or not ALLOW_SLUG_CHANGE:
self.cleaned_data['slug'] = slugify(self.cleaned_data['name'])
return self.cleaned_data['slug'][:50]
def clean(self):
super(CategoryBaseAdminForm, self).clean()
opts = self._meta
# Validate slug is valid in that level
kwargs = {}
if self.cleaned_data.get('parent', None) is None:
@ -91,14 +92,14 @@ class CategoryBaseAdminForm(forms.ModelForm):
else:
kwargs['parent__pk'] = int(self.cleaned_data['parent'].id)
this_level_slugs = [c['slug'] for c in opts.model.objects.filter(
**kwargs).values('id','slug'
**kwargs).values('id', 'slug'
) if c['id'] != self.instance.id]
if self.cleaned_data['slug'] in this_level_slugs:
raise forms.ValidationError("The slug must be unique among "
"the items at its level.")
# Validate Category Parent
# Make sure the category doesn't set itself or any of its children as
# Make sure the category doesn't set itself or any of its children as
# its parent.
decendant_ids = self.instance.get_descendants().values_list('id', flat=True)
if self.cleaned_data.get('parent', None) is None or self.instance.id is None:
@ -117,35 +118,36 @@ class CategoryBaseAdmin(TreeEditor, admin.ModelAdmin):
list_display = ('name', 'active')
search_fields = ('name',)
prepopulated_fields = {'slug': ('name',)}
actions = ['activate', 'deactivate']
def get_actions(self, request):
actions = super(CategoryBaseAdmin, self).get_actions(request)
if 'delete_selected' in actions:
del actions['delete_selected']
return actions
def deactivate(self, request, queryset):
"""
Set active to False for selected items
"""
selected_cats = self.model.objects.filter(
pk__in=[int(x) for x in request.POST.getlist('_selected_action')])
for item in selected_cats:
if item.active:
item.active = False
item.save()
item.children.all().update(active=False)
deactivate.short_description = "Deactivate selected categories and their children"
def activate(self, request, queryset):
"""
Set active to True for selected items
"""
selected_cats = self.model.objects.filter(
pk__in=[int(x) for x in request.POST.getlist('_selected_action')])
for item in selected_cats:
item.active = True
item.save()

View file

@ -8,4 +8,4 @@ if STATIC_URL == None:
STATIC_URL = settings.MEDIA_URL
MEDIA_PATH = getattr(settings, 'EDITOR_MEDIA_PATH', '%seditor/' % STATIC_URL)
TREE_INITIAL_STATE = getattr(settings, 'EDITOR_TREE_INITIAL_STATE', 'collapsed')
TREE_INITIAL_STATE = getattr(settings, 'EDITOR_TREE_INITIAL_STATE', 'collapsed')

View file

@ -1,6 +1,7 @@
import django
from django.db import models
from django.template import Library
from django.contrib.admin.templatetags.admin_list import result_headers
from django.contrib.admin.templatetags.admin_list import result_headers, _boolean_icon
try:
from django.contrib.admin.util import lookup_field, display_for_field, label_for_field
except ImportError:
@ -13,6 +14,7 @@ from django.utils.safestring import mark_safe
register = Library()
def items_for_tree_result(cl, result, form):
"""
Generates the actual list of data.
@ -27,6 +29,9 @@ def items_for_tree_result(cl, result, form):
result_repr = EMPTY_CHANGELIST_VALUE
else:
if f is None:
if django.VERSION[1] == 4:
if field_name == 'action_checkbox':
row_class = ' class="action-checkbox disclosure"'
allow_tags = getattr(attr, 'allow_tags', False)
boolean = getattr(attr, 'boolean', False)
if boolean:
@ -50,21 +55,26 @@ def items_for_tree_result(cl, result, form):
if isinstance(f, models.DateField) or isinstance(f, models.TimeField):
row_class = ' class="nowrap"'
if first:
try:
f, attr, checkbox_value = lookup_field('action_checkbox', result, cl.model_admin)
#result_repr = mark_safe("%s%s" % (value, result_repr))
if row_class:
row_class = "%s%s" % (row_class[:-1],' disclosure"')
else:
row_class = ' class="disclosure"'
except (AttributeError, ObjectDoesNotExist):
pass
if django.VERSION[1] < 4:
try:
f, attr, checkbox_value = lookup_field('action_checkbox', result, cl.model_admin)
#result_repr = mark_safe("%s%s" % (value, result_repr))
if row_class:
row_class = "%s%s" % (row_class[:-1], ' disclosure"')
else:
row_class = ' class="disclosure"'
except (AttributeError, ObjectDoesNotExist):
pass
if force_unicode(result_repr) == '':
result_repr = mark_safe('&nbsp;')
# If list_display_links not defined, add the link tag to the first field
if (first and not cl.list_display_links) or field_name in cl.list_display_links:
table_tag = 'td' #{True:'th', False:'td'}[first]
if django.VERSION[1] < 4:
table_tag = 'td' # {True:'th', False:'td'}[first]
else:
table_tag = {True:'th', False:'td'}[first]
url = cl.url_for_result(result)
# Convert the pk to something that can be used in Javascript.
# Problem cases are long ints (23L) and non-ASCII strings.
@ -75,8 +85,13 @@ def items_for_tree_result(cl, result, form):
value = result.serializable_value(attr)
result_id = repr(force_unicode(value))[1:]
first = False
yield mark_safe(u'<%s%s>%s<a href="%s"%s>%s</a></%s>' % \
(table_tag, row_class, checkbox_value, url, (cl.is_popup and ' onclick="opener.dismissRelatedLookupPopup(window, %s); return false;"' % result_id or ''), conditional_escape(result_repr), table_tag))
if django.VERSION[1] < 4:
yield mark_safe(u'<%s%s>%s<a href="%s"%s>%s</a></%s>' % \
(table_tag, row_class, checkbox_value, url, (cl.is_popup and ' onclick="opener.dismissRelatedLookupPopup(window, %s); return false;"' % result_id or ''), conditional_escape(result_repr), table_tag))
else:
yield mark_safe(u'<%s%s><a href="%s"%s>%s</a></%s>' % \
(table_tag, row_class, url, (cl.is_popup and ' onclick="opener.dismissRelatedLookupPopup(window, %s); return false;"' % result_id or ''), conditional_escape(result_repr), table_tag))
else:
# By default the fields come from ModelAdmin.list_editable, but if we pull
# the fields out of the form instead of list_editable custom admins
@ -90,9 +105,11 @@ def items_for_tree_result(cl, result, form):
if form and not form[cl.model._meta.pk.name].is_hidden:
yield mark_safe(u'<td>%s</td>' % force_unicode(form[cl.model._meta.pk.name]))
class TreeList(list):
pass
def tree_results(cl):
if cl.formset:
for res, form in zip(cl.result_list, cl.formset.forms):
@ -115,6 +132,7 @@ def tree_results(cl):
res.parent_pk = None
yield result
def result_tree_list(cl):
"""
Displays the headers and data list together

View file

@ -11,15 +11,16 @@ import django
import settings
class TreeEditorQuerySet(QuerySet):
"""
The TreeEditorQuerySet is a special query set used only in the TreeEditor
ChangeList page. The only difference to a regular QuerySet is that it
will enforce:
(a) The result is ordered in correct tree order so that
the TreeAdmin works all right.
(b) It ensures that all ancestors of selected items are included
in the result set, so the resulting tree display actually
makes sense.
@ -41,20 +42,20 @@ class TreeEditorQuerySet(QuerySet):
p.id not in include_pages:
ancestor_id_list = p.get_ancestors().values_list('id', flat=True)
include_pages.update(ancestor_id_list)
if include_pages:
qs = qs | self.model._default_manager.filter(id__in=include_pages)
qs = qs.distinct()
for obj in super(TreeEditorQuerySet, qs).iterator():
yield obj
# Although slicing isn't nice in a tree, it is used in the deletion action
# in the admin changelist. This causes github issue #25
# def __getitem__(self, index):
# return self # Don't even try to slice
def get(self, *args, **kwargs):
"""
Quick and dirty hack to fix change_view and delete_view; they use
@ -65,54 +66,56 @@ class TreeEditorQuerySet(QuerySet):
"""
return self.model._default_manager.get(*args, **kwargs)
class TreeChangeList(ChangeList):
def _get_default_ordering(self):
if django.VERSION[1] < 4:
return '', '' #('tree_id', 'lft')
return '', '' # ('tree_id', 'lft')
else:
return []
def get_ordering(self, request=None, queryset=None):
if django.VERSION[1] < 4:
return '', '' #('tree_id', 'lft')
return '', '' # ('tree_id', 'lft')
else:
return []
def get_query_set(self, *args, **kwargs):
qs = super(TreeChangeList, self).get_query_set(*args, **kwargs).order_by('tree_id', 'lft')
return qs
class TreeEditor(admin.ModelAdmin):
list_per_page = 999999999 # We can't have pagination
list_max_show_all = 200 # new in django 1.4
list_per_page = 999999999 # We can't have pagination
list_max_show_all = 200 # new in django 1.4
class Media:
css = {'all':(settings.MEDIA_PATH + "jquery.treeTable.css",)}
css = {'all': (settings.MEDIA_PATH + "jquery.treeTable.css", )}
js = []
js.extend((settings.MEDIA_PATH + "jquery.treeTable.js",))
js.extend((settings.MEDIA_PATH + "jquery.treeTable.js", ))
def __init__(self, *args, **kwargs):
super(TreeEditor, self).__init__(*args, **kwargs)
self.list_display = list(self.list_display)
if 'action_checkbox' in self.list_display:
self.list_display.remove('action_checkbox')
opts = self.model._meta
self.change_list_template = [
'admin/%s/%s/editor/tree_editor.html' % (opts.app_label, opts.object_name.lower()),
'admin/%s/editor/tree_editor.html' % opts.app_label,
'admin/editor/tree_editor.html',
]
def get_changelist(self, request, **kwargs):
"""
Returns the ChangeList class for use on the changelist page.
"""
return TreeChangeList
def old_changelist_view(self, request, extra_context=None):
"The 'change list' admin view for this model."
from django.contrib.admin.views.main import ERROR_FLAG
@ -137,15 +140,15 @@ class TreeEditor(admin.ModelAdmin):
try:
if django.VERSION[1] < 4:
params = (request, self.model, list_display,
self.list_display_links, self.list_filter, self.date_hierarchy,
self.search_fields, self.list_select_related,
self.list_per_page,self.list_editable, self)
params = (request, self.model, list_display,
self.list_display_links, self.list_filter, self.date_hierarchy,
self.search_fields, self.list_select_related,
self.list_per_page, self.list_editable, self)
else:
params = (request, self.model, list_display,
self.list_display_links, self.list_filter, self.date_hierarchy,
self.search_fields, self.list_select_related,
self.list_per_page, self.list_max_show_all,
params = (request, self.model, list_display,
self.list_display_links, self.list_filter, self.date_hierarchy,
self.search_fields, self.list_select_related,
self.list_per_page, self.list_max_show_all,
self.list_editable, self)
cl = TreeChangeList(*params)
except IncorrectLookupParameters:
@ -238,7 +241,7 @@ class TreeEditor(admin.ModelAdmin):
else:
selection_note_all = ungettext('%(total_count)s selected',
'All %(total_count)s selected', cl.result_count)
context.update({
'module_name': force_unicode(opts.verbose_name_plural),
'selection_note': _('0 of %(cnt)s selected') % {'cnt': len(cl.result_list)},
@ -253,7 +256,7 @@ class TreeEditor(admin.ModelAdmin):
'admin/%s/change_list.html' % app_label,
'admin/change_list.html'
], context, context_instance=context_instance)
def changelist_view(self, request, extra_context=None, *args, **kwargs):
"""
Handle the changelist view, the django view for the model instances
@ -267,7 +270,7 @@ class TreeEditor(admin.ModelAdmin):
request, extra_context, *args, **kwargs)
else:
return self.old_changelist_view(request, extra_context)
def queryset(self, request):
"""
Returns a QuerySet of all model instances that can be edited by the

View file

@ -3,8 +3,12 @@ Provides compatibility with Django 1.1
Copied from django.contrib.admin.util
"""
from django.forms.forms import pretty_name
from django.db import models
from django.db.models.related import RelatedObject
from django.utils.encoding import force_unicode, smart_unicode, smart_str
from django.utils import formats
def lookup_field(name, obj, model_admin=None):
opts = obj._meta
@ -81,10 +85,11 @@ def label_for_field(name, model, model_admin=None, return_attr=False):
else:
return label
def display_for_field(value, field):
from django.contrib.admin.templatetags.admin_list import _boolean_icon
from django.contrib.admin.views.main import EMPTY_CHANGELIST_VALUE
if field.flatchoices:
return dict(field.flatchoices).get(value, EMPTY_CHANGELIST_VALUE)
# NullBooleanField needs special-case null-handling, so it comes

View file

@ -2,6 +2,7 @@ from django.db.models import ForeignKey, ManyToManyField
from .models import Category
class CategoryM2MField(ManyToManyField):
def __init__(self, **kwargs):
if 'to' in kwargs:

View file

@ -1,4 +1,5 @@
from django.core.management.base import BaseCommand, CommandError
from django.core.management.base import BaseCommand
class Command(BaseCommand):
"""
@ -8,7 +9,7 @@ class Command(BaseCommand):
args = "[appname ...]"
can_import_settings = True
requires_model_validation = False
def handle(self, *args, **options):
"""
Alter the tables
@ -17,7 +18,7 @@ class Command(BaseCommand):
from south.db import db
except ImportError:
raise ImproperlyConfigured("South must be installed for this command to work")
from categories.migration import migrate_app
from categories import model_registry
if args:

View file

@ -1,4 +1,5 @@
from django.core.management.base import BaseCommand, CommandError
from django.core.management.base import BaseCommand
class Command(BaseCommand):
"""
@ -8,7 +9,7 @@ class Command(BaseCommand):
args = "appname modelname fieldname"
can_import_settings = True
requires_model_validation = False
def handle(self, *args, **options):
"""
Alter the tables
@ -17,10 +18,9 @@ class Command(BaseCommand):
from south.db import db
except ImportError:
raise ImproperlyConfigured("South must be installed for this command to work")
from categories.migration import drop_field
from categories import model_registry
if len(args) != 3:
print "You must specify an Application name, a Model name and a Field name"
drop_field(*args)

View file

@ -5,18 +5,19 @@ from django.db import transaction
from categories.models import Category
from categories.settings import SLUG_TRANSLITERATOR
class Command(BaseCommand):
"""Import category trees from a file."""
help = "Imports category tree(s) from a file. Sub categories must be indented by the same multiple of spaces or tabs."
args = "file_path [file_path ...]"
def get_indent(self, string):
"""
Look through the string and count the spaces
"""
indent_amt = 0
if string[0] == '\t':
return '\t'
for char in string:
@ -24,7 +25,7 @@ class Command(BaseCommand):
indent_amt += 1
else:
return ' ' * indent_amt
@transaction.commit_on_success
def make_category(self, string, parent=None, order=1):
"""
@ -42,20 +43,20 @@ class Command(BaseCommand):
parent.rght = cat.rght + 1
parent.save()
return cat
def parse_lines(self, lines):
"""
Do the work of parsing each line
"""
indent = ''
level = 0
if lines[0][0] == ' ' or lines[0][0] == '\t':
raise CommandError("The first line in the file cannot start with a space or tab.")
# This keeps track of the current parents at a given level
current_parents = {0: None}
for line in lines:
if len(line) == 0:
continue
@ -65,18 +66,18 @@ class Command(BaseCommand):
elif not line[0] in indent:
raise CommandError("You can't mix spaces and tabs for indents")
level = line.count(indent)
current_parents[level] = self.make_category(line, parent=current_parents[level-1])
current_parents[level] = self.make_category(line, parent=current_parents[level - 1])
else:
# We are back to a zero level, so reset the whole thing
current_parents = {0: self.make_category(line)}
current_parents[0]._tree_manager.rebuild()
def handle(self, *file_paths, **options):
"""
Handle the basic import
"""
import os
for file_path in file_paths:
if not os.path.isfile(file_path):
print "File %s not found." % file_path
@ -84,6 +85,5 @@ class Command(BaseCommand):
f = file(file_path, 'r')
data = f.readlines()
f.close()
self.parse_lines(data)

View file

@ -7,16 +7,17 @@ from django.core.files.storage import get_storage_class
from django.utils.translation import ugettext_lazy as _
from .settings import (RELATION_MODELS, RELATIONS, THUMBNAIL_UPLOAD_PATH,
from .settings import (RELATION_MODELS, RELATIONS, THUMBNAIL_UPLOAD_PATH,
THUMBNAIL_STORAGE)
from .base import CategoryBase
STORAGE = get_storage_class(THUMBNAIL_STORAGE)
class Category(CategoryBase):
thumbnail = models.FileField(
upload_to=THUMBNAIL_UPLOAD_PATH,
upload_to=THUMBNAIL_UPLOAD_PATH,
null=True, blank=True,
storage=STORAGE(),)
thumbnail_width = models.IntegerField(blank=True, null=True)
@ -28,8 +29,8 @@ class Category(CategoryBase):
max_length=100,
help_text="An alternative title to use on pages with this category.")
alternate_url = models.CharField(
blank=True,
max_length=200,
blank=True,
max_length=200,
help_text="An alternative URL to use instead of the one derived from "
"the category hierarchy.")
description = models.TextField(blank=True, null=True)
@ -43,20 +44,19 @@ class Category(CategoryBase):
default="",
help_text="(Advanced) Any additional HTML to be placed verbatim "
"in the &lt;head&gt;")
@property
def short_title(self):
return self.name
def get_absolute_url(self):
"""Return a path"""
if self.alternate_url:
return self.alternate_url
prefix = reverse('categories_tree_list')
ancestors = list(self.get_ancestors()) + [self,]
ancestors = list(self.get_ancestors()) + [self, ]
return prefix + '/'.join([force_unicode(i.slug) for i in ancestors]) + '/'
if RELATION_MODELS:
def get_related_content_type(self, content_type):
"""
@ -64,13 +64,13 @@ class Category(CategoryBase):
"""
return self.categoryrelation_set.filter(
content_type__name=content_type)
def get_relation_type(self, relation_type):
"""
Get all relations of the specified relation type
"""
return self.categoryrelation_set.filter(relation_type=relation_type)
def save(self, *args, **kwargs):
if self.thumbnail:
from django.core.files.images import get_image_dimensions
@ -81,23 +81,25 @@ class Category(CategoryBase):
width, height = get_image_dimensions(self.thumbnail.file, close=True)
else:
width, height = None, None
self.thumbnail_width = width
self.thumbnail_height = height
super(Category, self).save(*args, **kwargs)
class Meta(CategoryBase.Meta):
verbose_name_plural = 'categories'
class MPTTMeta:
order_insertion_by = ('order', 'name')
if RELATIONS:
CATEGORY_RELATION_LIMITS = reduce(lambda x,y: x|y, RELATIONS)
CATEGORY_RELATION_LIMITS = reduce(lambda x, y: x | y, RELATIONS)
else:
CATEGORY_RELATION_LIMITS = []
class CategoryRelationManager(models.Manager):
def get_content_type(self, content_type):
"""
@ -105,7 +107,7 @@ class CategoryRelationManager(models.Manager):
"""
qs = self.get_query_set()
return qs.filter(content_type__name=content_type)
def get_relation_type(self, relation_type):
"""
Get all the items of the given relationship type related to this item.
@ -113,6 +115,7 @@ class CategoryRelationManager(models.Manager):
qs = self.get_query_set()
return qs.filter(relation_type=relation_type)
class CategoryRelation(models.Model):
"""Related category item"""
category = models.ForeignKey(Category)
@ -120,13 +123,13 @@ class CategoryRelation(models.Model):
ContentType, limit_choices_to=CATEGORY_RELATION_LIMITS)
object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey('content_type', 'object_id')
relation_type = models.CharField(_("Relation Type"),
max_length="200",
blank=True,
relation_type = models.CharField(_("Relation Type"),
max_length="200",
blank=True,
null=True,
help_text=_("A generic text field to tag a relation, like 'leadphoto'."))
objects = CategoryRelationManager()
def __unicode__(self):
return u"CategoryRelation"

View file

@ -1,5 +1,3 @@
{% for item in category.get_ancestors %}
<a href="{{ item.get_absolute_url }}">{{ item.name }}</a>
{{ separator }}
{% endfor %}
{{ category.name }}
{% spaceless %}{% for item in category.get_ancestors %}
<a href="{{ item.get_absolute_url }}">{{ item.name }}</a>{{ separator }}{% endfor %}{{ category.name }}
{% endspaceless %}

View file

@ -1,4 +1,4 @@
{% load category_tags %}
{% load category_tags %}{% spaceless %}
<ul><li><a href="{% url categories_tree_list %}">Top</a>
{% for node,structure in path|tree_info %}
{% if structure.new_level %}<ul><li>
@ -8,4 +8,4 @@
{% else %}<a href="{{ node.get_absolute_url }}">{{ node.name }}</a>
{% endifequal %}
{% for level in structure.closed_levels %}</li></ul>{% endfor %}
{% endfor %}</li></ul>
{% endfor %}</li></ul>{% endspaceless %}

View file

@ -1,35 +1,60 @@
from django import template
from django.template import Library, Node, TemplateSyntaxError, \
Variable, resolve_variable, VariableDoesNotExist, Context
from django.db.models import get_model
from django.template import (Node, TemplateSyntaxError, VariableDoesNotExist,
FilterExpression)
from categories.base import CategoryBase
from categories.models import Category
from mptt.utils import drilldown_tree_for_node
from mptt.templatetags.mptt_tags import tree_path, tree_info
from mptt.templatetags.mptt_tags import (tree_path, tree_info, RecurseTreeNode,
full_tree_for_model)
register = template.Library()
register.filter("category_path", tree_path)
register.filter(tree_info)
register.tag("full_tree_for_category", full_tree_for_model)
def get_category(category_string):
def resolve(var, context):
try:
return var.resolve(context)
except VariableDoesNotExist:
try:
return var.var
except AttributeError:
return var
def get_cat_model(model):
"""
Return a class from a string or class
"""
try:
if isinstance(model, basestring):
model_class = get_model(*model.split("."))
elif issubclass(model, CategoryBase):
model_class = model
if model_class is None:
raise TypeError
except TypeError:
raise TemplateSyntaxError("Unknown model submitted: %s" % model)
return model_class
def get_category(category_string, model=Category):
"""
Convert a string, including a path, and return the Category object
"""
if category_string.startswith('"') and category_string.endswith('"'):
category = category_string[1:-1]
else:
category = category_string
if category.startswith('/'):
category = category[1:]
if category.endswith('/'):
category = category[:-1]
model_class = get_cat_model(model)
category = category_string.strip("'\"")
category = category.strip('/')
cat_list = category.split('/')
if len(cat_list) == 0:
return None
try:
categories = Category.objects.filter(name = cat_list[-1], level=len(cat_list)-1)
categories = model_class.objects.filter(name=cat_list[-1],
level=len(cat_list) - 1)
if len(cat_list) == 1 and len(categories) > 1:
return None
# If there is only one, use it. If there is more than one, check
@ -40,30 +65,32 @@ def get_category(category_string):
for item in categories:
if item.parent.name == cat_list[-2]:
return item
except Category.DoesNotExist:
except model_class.DoesNotExist:
return None
class CategoryDrillDownNode(template.Node):
def __init__(self, category, varname):
self.category = template.Variable(category)
def __init__(self, category, varname, model):
self.category = category
self.varname = varname
self.model = model
def render(self, context):
category = resolve(self.category, context)
if isinstance(category, CategoryBase):
cat = category
else:
cat = get_category(category, self.model)
try:
category = self.category.resolve(context)
except template.VariableDoesNotExist:
category = self.category.var
try:
if category is not None:
context[self.varname] = drilldown_tree_for_node(category)
if cat is not None:
context[self.varname] = drilldown_tree_for_node(cat)
else:
context[self.varname] = []
except Category.DoesNotExist:
except:
context[self.varname] = []
return ''
@register.tag
def get_category_drilldown(parser, token):
"""
@ -72,11 +99,11 @@ def get_category_drilldown(parser, token):
Syntax::
{% get_category_drilldown "category name" as varname %}
{% get_category_drilldown "category name" [using "app.Model"] as varname %}
Example::
{% get_category_drilldown "/Grandparent/Parent" as family %}
{% get_category_drilldown "/Grandparent/Parent" [using "app.Model"] as family %}
or ::
@ -86,30 +113,44 @@ def get_category_drilldown(parser, token):
Grandparent, Parent, Child 1, Child 2, Child n
"""
bits = token.contents.split()
bits = token.split_contents()
error_str = '%(tagname)s tag should be in the format {%% %(tagname)s ' \
'"category name" as varname %%}.'
if len(bits) != 4 or bits[2] != 'as':
raise template.TemplateSyntaxError, error_str % {'tagname': bits[0]}
category = bits[1]
varname = bits[3]
return CategoryDrillDownNode(category, varname)
'"category name" [using "app.Model"] as varname %%} or ' \
'{%% %(tagname)s category_obj as varname %%}.'
if len(bits) == 4:
if bits[2] != 'as':
raise template.TemplateSyntaxError, error_str % {'tagname': bits[0]}
if bits[2] == 'as':
varname = bits[3].strip("'\"")
model = "categories.category"
if len(bits) == 6:
if bits[2] not in ('using', 'as') or bits[4] not in ('using', 'as'):
raise template.TemplateSyntaxError, error_str % {'tagname': bits[0]}
if bits[2] == 'as':
varname = bits[3].strip("'\"")
model = bits[5].strip("'\"")
if bits[2] == 'using':
varname = bits[5].strip("'\"")
model = bits[3].strip("'\"")
category = FilterExpression(bits[1], parser)
return CategoryDrillDownNode(category, varname, model)
@register.inclusion_tag('categories/breadcrumbs.html')
def breadcrumbs(category,separator="/"):
def breadcrumbs(category_string, separator=' > ', using='categories.category'):
"""
{% breadcrumbs category separator="::" using="categories.category" %}
Render breadcrumbs, using the ``categories/breadcrumbs.html`` template,
using the optional ``separator`` argument.
"""
if isinstance(category, CategoryBase):
cat = category
else:
cat = get_category(category)
cat = get_category(category_string, using)
return {'category': cat, 'separator': separator}
@register.inclusion_tag('categories/ul_tree.html')
def display_drilldown_as_ul(category):
def display_drilldown_as_ul(category, using='categories.Category'):
"""
Render the category with ancestors and children using the
``categories/ul_tree.html`` template.
@ -142,15 +183,12 @@ def display_drilldown_as_ul(category):
</li>
</ul>
"""
if isinstance(category, CategoryBase):
cat = category
else:
cat = get_category(category)
cat = get_category(category, using)
return {'category': cat, 'path': drilldown_tree_for_node(cat) or []}
@register.inclusion_tag('categories/ul_tree.html')
def display_path_as_ul(category):
def display_path_as_ul(category, using='categories.Category'):
"""
Render the category with ancestors, but no children using the
``categories/ul_tree.html`` template.
@ -180,14 +218,18 @@ def display_path_as_ul(category):
return {'category': cat, 'path': cat.get_ancestors() or []}
class TopLevelCategoriesNode(template.Node):
def __init__(self, varname):
def __init__(self, varname, model):
self.varname = varname
self.model = model
def render(self, context):
context[self.varname] = Category.objects.filter(parent=None).order_by('name')
model = get_cat_model(self.model)
context[self.varname] = model.objects.filter(parent=None).order_by('name')
return ''
@register.tag
def get_top_level_categories(parser, token):
"""
@ -195,31 +237,31 @@ def get_top_level_categories(parser, token):
Syntax::
{% get_top_level_categories as categories %}
{% get_top_level_categories [using "app.Model"] as categories %}
Returns an list of categories [<category>, <category>, <category, ...]
"""
bits = token.contents.split()
if len(bits) != 3:
raise template.TemplateSyntaxError(
"Usage: {%% %s as <variable> %%}" % bits[0]
)
if bits[1] != 'as':
raise template.TemplateSyntaxError(
"Usage: {%% %s as <variable> %%}" % bits[0]
)
return TopLevelCategoriesNode(bits[2])
bits = token.split_contents()
usage = 'Usage: {%% %s [using "app.Model"] as <variable> %%}' % bits[0]
if len(bits) == 3:
if bits[1] != 'as':
raise template.TemplateSyntaxError(usage)
varname = bits[2]
model = "categories.category"
elif len(bits) == 5:
if bits[1] not in ('as', 'using') and bits[3] not in ('as', 'using'):
raise template.TemplateSyntaxError(usage)
if bits[1] == 'using':
model = bits[2].strip("'\"")
varname = bits[4].strip("'\"")
else:
model = bits[4].strip("'\"")
varname = bits[2].strip("'\"")
def resolve(var, context):
try:
return var.resolve(context)
except VariableDoesNotExist:
try:
return var.var
except AttributeError:
return var
return TopLevelCategoriesNode(varname, model)
def get_latest_objects_by_category(category, app_label, model_name, set_name,
def get_latest_objects_by_category(category, app_label, model_name, set_name,
date_field='pub_date', num=15):
m = get_model(app_label, model_name)
if not isinstance(category, CategoryBase):
@ -229,79 +271,75 @@ def get_latest_objects_by_category(category, app_label, model_name, set_name,
for cat in list(children) + [category]:
if hasattr(cat, '%s_set' % set_name):
ids.extend([x.pk for x in getattr(cat, '%s_set' % set_name).all()[:num]])
return m.objects.filter(pk__in=ids).order_by('-%s' % date_field)[:num]
class LatestObjectsNode(Node):
def __init__(self, var_name, category, app_label, model_name, set_name,
def __init__(self, var_name, category, app_label, model_name, set_name,
date_field='pub_date', num=15):
"""Get latest objects of app_label.model_name"""
self.category = Variable(category)
self.app_label = Variable(app_label)
self.model_name = Variable(model_name)
self.set_name = Variable(set_name)
self.date_field = Variable(date_field)
self.num = Variable(num)
"""
Get latest objects of app_label.model_name
"""
self.category = category
self.app_label = app_label
self.model_name = model_name
self.set_name = set_name
self.date_field = date_field
self.num = num
self.var_name = var_name
def get_cache_key(self, category, app_label, model_name, set_name,
date_field, num):
"""Get the cache key"""
key = 'latest_objects.%s' % '.'.join([category, app_label, model_name,
set_name, date_field, num])
def render(self, context):
"""Render this sucker"""
"""
Render this sucker
"""
category = resolve(self.category, context)
app_label = resolve(self.app_label, context)
model_name = resolve(self.model_name, context)
set_name = resolve(self.set_name, context)
date_field = resolve(self.date_field, context)
num = resolve(self.num, context)
cache_key = self.get_cache_key(category, app_label, model_name, set_name,
date_field, num)
result = cache.get(cache_key)
if not result:
result = get_latest_objects_by_category(category, app_label, model_name,
result = get_latest_objects_by_category(category, app_label, model_name,
set_name, date_field, num)
cache.set(key, result, 300)
context[self.var_name] = result
return ''
def do_get_latest_objects_by_category(parser, token):
"""
Get the latest objects by category
{% get_latest_objects_by_category category app_name model_name set_name [date_field] [number] as [var_name] %}
"""
proper_form = "{% get_latest_objects_by_category category app_name model_name set_name [date_field] [number] as [var_name] %}"
bits = token.split_contents()
if bits[-2] != 'as':
raise TemplateSyntaxError("%s tag shoud be in the form: %s" % (bits[0], proper_form))
if len(bits) < 7:
raise TemplateSyntaxError("%s tag shoud be in the form: %s" % (bits[0], proper_form))
if len(bits) > 9:
raise TemplateSyntaxError("%s tag shoud be in the form: %s" % (bits[0], proper_form))
category = bits[1]
app_label = bits[2]
model_name = bits[3]
set_name = bits[4]
category = FilterExpression(bits[1], parser)
app_label = FilterExpression(bits[2], parser)
model_name = FilterExpression(bits[3], parser)
set_name = FilterExpression(bits[4], parser)
var_name = bits[-1]
if bits[5] != 'as':
date_field = bits[5]
date_field = FilterExpression(bits[5], parser)
else:
date_field = None
date_field = FilterExpression(None, parser)
if bits[6] != 'as':
num = bits[6]
num = FilterExpression(bits[6], parser)
else:
num = None
return LatestObjectsNode(var_name, category, app_label, model_name, set_name,
num = FilterExpression(None, parser)
return LatestObjectsNode(var_name, category, app_label, model_name, set_name,
date_field, num)
register.tag("get_latest_objects_by_category", do_get_latest_objects_by_category)
@register.filter
def tree_queryset(value):
@ -313,7 +351,7 @@ def tree_queryset(value):
from copy import deepcopy
if not isinstance(value, QuerySet):
return value
qs = value
qs2 = deepcopy(qs)
# Reaching into the bowels of query sets to find out whether the qs is
@ -331,9 +369,41 @@ def tree_queryset(value):
p.id not in include_pages:
ancestor_id_list = p.get_ancestors().values_list('id', flat=True)
include_pages.update(ancestor_id_list)
if include_pages:
qs = qs | qs.model._default_manager.filter(id__in=include_pages)
qs = qs.distinct()
return qs
return qs
@register.tag
def recursetree(parser, token):
"""
Iterates over the nodes in the tree, and renders the contained block for each node.
This tag will recursively render children into the template variable {{ children }}.
Only one database query is required (children are cached for the whole tree)
Usage:
<ul>
{% recursetree nodes %}
<li>
{{ node.name }}
{% if not node.is_leaf_node %}
<ul>
{{ children }}
</ul>
{% endif %}
</li>
{% endrecursetree %}
</ul>
"""
bits = token.contents.split()
if len(bits) != 2:
raise template.TemplateSyntaxError('%s tag requires a queryset' % bits[0])
queryset_var = FilterExpression(bits[1], parser)
template_nodes = parser.parse(('endrecursetree',))
parser.delete_first_token()
return RecurseTreeNode(template_nodes, queryset_var)

View file

@ -1,64 +1,62 @@
# test spaces in hierarchy
# test tabs in hierarchy
# test mixed
import unittest, os
import unittest
import os
from categories.models import Category
from categories.management.commands.import_categories import Command
from django.core.management.base import CommandError
class CategoryImportTest(unittest.TestCase):
def setUp(self):
pass
def _import_file(self, filename):
root_cats = ['Category 1', 'Category 2', 'Category 3']
testfile = os.path.abspath(os.path.join(os.path.dirname(os.path.dirname(__file__)), 'fixtures', filename))
cmd = Command()
cmd.execute(testfile)
roots = Category.tree.root_nodes()
self.assertEqual(len(roots), 3)
for item in roots:
assert item.name in root_cats
cat2 = Category.objects.get(name='Category 2')
cat21 = cat2.children.all()[0]
self.assertEqual(cat21.name, 'Category 2-1')
cat211 = cat21.children.all()[0]
self.assertEqual(cat211.name, 'Category 2-1-1')
def testImportSpaceDelimited(self):
Category.objects.all().delete()
self._import_file('test_category_spaces.txt')
items = Category.objects.all()
self.assertEqual(items[0].name, 'Category 1')
self.assertEqual(items[1].name, 'Category 1-1')
self.assertEqual(items[2].name, 'Category 1-2')
def testImportTabDelimited(self):
Category.objects.all().delete()
self._import_file('test_category_tabs.txt')
items = Category.objects.all()
self.assertEqual(items[0].name, 'Category 1')
self.assertEqual(items[1].name, 'Category 1-1')
self.assertEqual(items[2].name, 'Category 1-2')
def testMixingTabsSpaces(self):
"""
Should raise an exception.
"""
string1 = ["cat1"," cat1-1", "\tcat1-2-FAIL!",""]
string2 = ["cat1","\tcat1-1"," cat1-2-FAIL!",""]
string1 = ["cat1", " cat1-1", "\tcat1-2-FAIL!", ""]
string2 = ["cat1", "\tcat1-1", " cat1-2-FAIL!", ""]
cmd = Command()
# raise Exception
self.assertRaises(CommandError, cmd.parse_lines, string1)
self.assertRaises(CommandError, cmd.parse_lines, string2)

View file

@ -1,23 +1,22 @@
# test active returns only active items
import unittest, os
import unittest
from categories.models import Category
from categories.management.commands.import_categories import Command
from django.core.management.base import CommandError
class CategoryManagerTest(unittest.TestCase):
def setUp(self):
pass
def testActive(self):
"""
Should raise an exception.
"""
all_count = Category.objects.all().count()
self.assertEqual(Category.objects.active().count(), all_count)
cat1 = Category.objects.get(name='Category 1')
cat1.active = False
cat1.save()
active_count = all_count - cat1.get_descendants(True).count()
self.assertEqual(Category.objects.active().count(), active_count)

View file

@ -1,11 +1,13 @@
from django.test import TestCase
from django import template
from categories.models import Category
class CategoryTagsTest(TestCase):
class GetCategoryTest(TestCase):
fixtures = ['musicgenres.json']
def render_template(self, template_string, context={}):
"""
Return the rendered string or raise an exception.
@ -16,27 +18,50 @@ class GetCategoryTest(TestCase):
def testTooFewArguments(self):
"""
Ensure that get_cateogry raises an exception if there aren't enough arguments.
Ensure that get_category raises an exception if there aren't enough arguments.
"""
self.assertRaises(template.TemplateSyntaxError, self.render_template, '{% load category_tags %}{% get_category %}')
def testTooManyArguments(self):
"""
Ensure that get_category raises an exception if there are too many arguments.
"""
self.assertRaises(template.TemplateSyntaxError, self.render_template, '{% load category_tags %}{% get_category "/Rock" as too many arguments %}')
def testAsIsSecondArgument(self):
"""
Test that the second argument to get_category is 'as'.
"""
self.assertRaises(template.TemplateSyntaxError, self.render_template, '{% load category_tags %}{% get_category "Rock" notas rock %}')
def testBasicUsage(self):
"""
Test that we can properly retrieve a category.
"""
rock_resp = u'\n<ul><li><a href="/categories/">Top</a>\n</li></ul>'
# display_path_as_ul
rock_resp = u'<ul><li><a href="/categories/">Top</a></li></ul>'
resp = self.render_template('{% load category_tags %}{% display_path_as_ul "/Rock" %}')
self.assertEqual(resp, rock_resp)
# display_drilldown_as_ul
expected_resp = u'<ul><li><a href="/categories/">Top</a><ul><li><a href="/categories/world/">World</a><ul><li><strong>Worldbeat</strong><ul><li><a href="/categories/world/worldbeat/afrobeat/">Afrobeat</a></li></ul></li></ul></li></ul></li></ul>'
resp = self.render_template('{% load category_tags %}'
'{% display_drilldown_as_ul "/World/Worldbeat" using="categories.category" %}')
self.assertEqual(resp, expected_resp)
# breadcrumbs
expected_resp = u'<a href="/categories/world/">World</a> &gt; Worldbeat'
resp = self.render_template('{% load category_tags %}'
'{% breadcrumbs "/World/Worldbeat" using="categories.category" %}')
self.assertEqual(resp, expected_resp)
# get_top_level_categories
expected_resp = u'Avant-garde|Blues|Country|Easy listening|Electronic|Hip hop/Rap music|Jazz|Latin|Modern folk|Pop|Reggae|Rhythm and blues|Rock|World|'
resp = self.render_template('{% load category_tags %}'
'{% get_top_level_categories using "categories.category" as varname %}'
'{% for item in varname %}{{ item }}|{% endfor %}')
self.assertEqual(resp, expected_resp)
# get_category_drilldown
expected_resp = u"World|World &gt; Worldbeat|"
resp = self.render_template('{% load category_tags %}'
'{% get_category_drilldown "/World" using "categories.category" as var %}'
'{% for item in var %}{{ item }}|{% endfor %}')
self.assertEqual(resp, expected_resp)
# recursetree
expected_resp = u'<ul><li>Country<ul><li>Country pop<ul><li>Urban Cowboy</li></ul></li></ul></li><li>World<ul><li>Worldbeat<ul></ul></li></ul></li></ul>'
ctxt = {'nodes': Category.objects.filter(name__in=("Worldbeat", "Urban Cowboy"))}
resp = self.render_template('{% load category_tags %}'
'<ul>{% recursetree nodes|tree_queryset %}<li>{{ node.name }}'
'{% if not node.is_leaf_node %}<ul>{{ children }}'
'</ul>{% endif %}</li>{% endrecursetree %}</ul>', ctxt)
self.assertEqual(resp, expected_resp)

View file

@ -13,4 +13,4 @@ urlpatterns = patterns('django.views.generic.list_detail',
urlpatterns += patterns('categories.views',
url(r'^(?P<path>.+)/$', 'category_detail', name='categories_category'),
)
)

View file

@ -10,20 +10,21 @@ from django.utils.translation import ugettext_lazy as _
from .models import Category
from .settings import CACHE_VIEW_LENGTH
@cache_page(CACHE_VIEW_LENGTH)
def category_detail(request, path,
def category_detail(request, path,
template_name='categories/category_detail.html', extra_context={}):
path_items = path.strip('/').split('/')
if len(path_items) >= 2:
category = get_object_or_404(Category,
slug__iexact = path_items[-1],
level = len(path_items)-1,
slug__iexact=path_items[-1],
level=len(path_items) - 1,
parent__slug__iexact=path_items[-2])
else:
category = get_object_or_404(Category,
slug__iexact = path_items[-1],
level = len(path_items)-1)
slug__iexact=path_items[-1],
level=len(path_items) - 1)
templates = []
while path_items:
templates.append('categories/%s.html' % '_'.join(path_items))
@ -31,7 +32,7 @@ def category_detail(request, path,
templates.append(template_name)
context = RequestContext(request)
context.update({'category':category})
context.update({'category': category})
if extra_context:
context.update(extra_context)
return HttpResponse(select_template(templates).render(context))
@ -41,13 +42,13 @@ def get_category_for_path(path, queryset=Category.objects.all()):
path_items = path.strip('/').split('/')
if len(path_items) >= 2:
queryset = queryset.filter(
slug__iexact = path_items[-1],
level = len(path_items)-1,
slug__iexact=path_items[-1],
level=len(path_items) - 1,
parent__slug__iexact=path_items[-2])
else:
queryset = queryset.filter(
slug__iexact = path_items[-1],
level = len(path_items)-1)
slug__iexact=path_items[-1],
level=len(path_items) - 1)
return queryset.get()
try:
@ -72,13 +73,13 @@ if ((django.VERSION[0] >= 1 and django.VERSION[1] >= 3) or HAS_CBV):
raise AttributeError(u"Category detail view %s must be called with "
u"a %s." % self.__class__.__name__, self.path_field)
if self.queryset is None:
queryset = self.get_queryset()
queryset = self.get_queryset()
try:
return get_category_for_path(self.kwargs[self.path_field])
except ObjectDoesNotExist:
raise Http404(_(u"No %(verbose_name)s found matching the query") %
{'verbose_name': queryset.model._meta.verbose_name})
def get_template_names(self):
names = []
path_items = self.kwargs[self.path_field].strip('/').split('/')
@ -88,16 +89,14 @@ if ((django.VERSION[0] >= 1 and django.VERSION[1] >= 3) or HAS_CBV):
names.extend(super(CategoryDetailView, self).get_template_names())
return names
class CategoryRelatedDetail(DetailView):
path_field = 'category_path'
object_name_field = None
def get_object(self, **kwargs):
queryset = super(CategoryRelatedDetail, self).get_queryset()
category = get_category_for_path(self.kwargs[self.path_field])
return queryset.get(category=category,slug=self.kwargs[self.slug_field])
return queryset.get(category=category, slug=self.kwargs[self.slug_field])
def get_template_names(self):
names = []
@ -106,22 +105,22 @@ if ((django.VERSION[0] >= 1 and django.VERSION[1] >= 3) or HAS_CBV):
if self.object_name_field:
path_items.append(getattr(self.object, self.object_name_field))
while path_items:
names.append( '%s/category_%s_%s%s.html' % (opts.app_label,
'_'.join(path_items),
opts.object_name.lower(),
self.template_name_suffix)
)
names.append('%s/category_%s_%s%s.html' % (
opts.app_label,
'_'.join(path_items),
opts.object_name.lower(),
self.template_name_suffix)
)
path_items.pop()
names.append('%s/category_%s%s.html' % (opts.app_label,
opts.object_name.lower(),
self.template_name_suffix)
)
names.append('%s/category_%s%s.html' % (
opts.app_label,
opts.object_name.lower(),
self.template_name_suffix)
)
names.extend(super(CategoryRelatedDetail, self).get_template_names())
return names
class CategoryRelatedList(ListView):
path_field = 'category_path'
def get_queryset(self):
@ -135,15 +134,17 @@ if ((django.VERSION[0] >= 1 and django.VERSION[1] >= 3) or HAS_CBV):
opts = self.object_list.model._meta
path_items = self.kwargs[self.path_field].strip('/').split('/')
while path_items:
names.append( '%s/category_%s_%s%s.html' % (opts.app_label,
'_'.join(path_items),
opts.object_name.lower(),
self.template_name_suffix)
)
names.append('%s/category_%s_%s%s.html' % (
opts.app_label,
'_'.join(path_items),
opts.object_name.lower(),
self.template_name_suffix)
)
path_items.pop()
names.append('%s/category_%s%s.html' % (opts.app_label,
opts.object_name.lower(),
self.template_name_suffix)
)
names.append('%s/category_%s%s.html' % (
opts.app_label,
opts.object_name.lower(),
self.template_name_suffix)
)
names.extend(super(CategoryRelatedList, self).get_template_names())
return names

View file

@ -62,7 +62,7 @@ div.clearer {
.headerButton a:hover {
color: white;
background-color: #787878;
}
li#toc_button {
@ -121,7 +121,7 @@ right:0;
top: 84px;
bottom: 19px;
left: 0px;
width: 229px;
width: 229px;
background-color: #E4EBF7;
border-right: 1px solid #ACACAC;
border-top: 1px solid #2B334F;
@ -362,7 +362,7 @@ p.topic-title {
border:1px solid #111111;
margin:30px;
}
.admonition p {
.admonition p {
font: 12px 'Lucida Grande', Geneva, Helvetica, Arial, sans-serif;
margin-top: 7px;
margin-bottom: 0px;
@ -411,7 +411,7 @@ table.docutils td, table.docutils th {
table.docutils th {
font-weight: bold;
}
/* This alternates colors in up to six table rows (light blue for odd, white for even)*/
/* This alternates colors in up to six table rows (light blue for odd, white for even)*/
.docutils tr {
background: #F0F5F9;
}
@ -453,6 +453,7 @@ th {
dl {
margin-bottom: 15px;
font-size: 12px;
}
dd p {
@ -544,7 +545,7 @@ td.linenos pre {
}
td.code {
}
table.highlighttable {
@ -562,7 +563,6 @@ table.highlighttable td.linenos {
}
tt {
font-family:"Bitstream Vera Sans Mono",Monaco,"Lucida Console",Courier,Consolas,monospace;
}
tt.descname {
@ -643,7 +643,7 @@ dl.class dd dl.method dt {
padding: 3px;
background-color: #e9e9e9;
border-top: none;
}
dl.function dt {
@ -659,7 +659,7 @@ margin:0 0 0 30px;
padding:0 0 12px 6px;
}
#docstitle {
height: 36px;
height: 36px;
background-image: url(header_sm_mid.png);
left: 0;
top: 0;

View file

@ -18,7 +18,7 @@ For many cases, you want a simple user-managed lookup table. You can do this wit
#. Create a subclass of CategoryBaseAdmin.
.. literalinclude:: code_examples/custom_categories1.py
.. literalinclude:: code_examples/custom_categories2.py
:linenos:
#. Register your model and custom model admin class.

View file

@ -6,27 +6,17 @@ Django Categories grew out of our need to provide a basic hierarchical taxonomy
As a news site, our stories, photos, and other content get divided into "sections" and we wanted all the apps to use the same set of sections. As our needs grew, the Django Categories grew in the functionality it gave to category handling within web pages.
New in 1.0
New in 1.1
==========
**Abstract Base Class for generic hierarchical category models**
When you want a multiple types of categories and don't want them all part of the same model, you can now easily create new models by subclassing ``CategoryBase``. You can also add additional metadata as necessary.
Your model's can subclass ``CategoryBaseAdminForm`` and ``CategoryBaseAdmin`` to get the hierarchical management in the admin.
See the docs for more information.
* Fixed a cosmetic bug in the Django 1.4 admin. Action checkboxes now only appear once.
**Increased the default caching time on views**
The default setting for ``CACHE_VIEW_LENGTH`` was ``0``, which means it would tell the browser to *never* cache the page. It is now ``600``, which is the default for `CACHE_MIDDLEWARE_SECONDS <https://docs.djangoproject.com/en/1.3/ref/settings/#cache-middleware-seconds>`_
* Template tags are refactored to allow easy use of any model derived from ``CategoryBase``.
**Updated for use with Django-MPTT 0.5**
Just a few tweaks.
* Improved test suite.
**Initial compatibility with Django 1.4**
More is coming, but at least it works.
* Improved some of the documentation.
**Slug transliteration for non-ASCII characters**
A new setting, ``SLUG_TRANSLITERATOR``, allows you to specify a function for converting the non-ASCII characters to ASCII characters before the slugification. Works great with `Unidecode <http://pypi.python.org/pypi/Unidecode>`_.
Contents

View file

@ -1,33 +1,146 @@
=============
Template Tags
=============
=========================
Template tags and filters
=========================
get_top_level_categories
========================
.. contents::
:depth: 2
:local:
:backlinks: top
Retrieves an alphabetical list of all the categories that have no parents.
Syntax:
Filters
=======
``category_path``
-----------------
**Optional Parameter:** separator string. *Default:* ``" :: "``
Creates a path represented by a categories by joining the items with a separator.
Each path item will be coerced to unicode, so you can pass a list of category instances, if required.
**Example using a list of categories:**
.. code-block:: django
{% get_top_level_categories as categories %}
{{ some_list|category_path }}
Returns an list of categories ``[<category>, <category>, <category, ...]``
If ``some_list`` is ``[ <Category: Country>, <Category: Country pop>, <Category: Urban Cowboy>]`` the result will be::
Country :: Country pop :: Urban Cowboy
**Example using a category node and optional separator parameter:**
.. code-block:: django
{{ some_node.get_ancestors|category_path:" > " }}
If ``some_node`` was category "Urban Cowboy", the result will be::
Country > Country pop > Urban Cowboy
.. _tree_info:
``tree_info``
-------------
**Optional Parameter:** ``"ancestors"``
Given a list of categories, it iterates over the list, generating a tuple of the current category and a dict containing information about the tree structure around it, with the following keys:
``'new_level'``
``True`` if the current item is the start of a new level in the tree, ``False`` otherwise.
``'closed_levels'``
A list of levels which end after the current item. This will be an empty list if the next category's level is the same as or greater than the level of the current item.
Provide the optional argument, ``"ancestors"``, to add a list of unicode representations of the ancestors of the current category, in descending order (root node first, immediate parent last), under the key 'ancestors'.
For example: given the sample tree below, the contents of the list which would be available under the 'ancestors' key are given on the right::
Country -> []
Country pop -> [u'Country pop']
Urban Cowboy -> [u'Country', u'Country pop']
Using this filter with unpacking in a {% for %} tag, you should have enough information about the tree structure to create a hierarchical representation of the tree.
.. code-block:: django
{% for node,structure in objects|tree_info %}
{% if structure.new_level %}<ul><li>{% else %}</li><li>{% endif %}
{{ node.name }}
{% for level in structure.closed_levels %}</li></ul>{% endfor %}
{% endfor %}
``tree_queryset``
-----------------
Convert a regular category :py:class:`QuerySet` into a new, ordered :py:class:`QuerySet` that includes the categories selected and their ancestors.
This is especially helpful when you have a subset of categories and want to show the hierarchy for all the items.
For example, if we add it to the example for :ref:`tree_info`:
.. code-block:: django
{% for node,structure in objects|tree_queryset|tree_info %}
{% if structure.new_level %}<ul><li>{% else %}</li><li>{% endif %}
{{ node.name }}
{% for level in structure.closed_levels %}</li></ul>{% endfor %}
{% endfor %}
A list of unrelated categories such as ``[<Category: Urban cowboy>, <Category: Urban comtemporary>]``, the above template example will output the two categories and their ancestors:
.. code-block:: html
<ul><li>
Country
<ul><li>
Country pop
<ul><li>
Urban cowboy
</li></ul></li></ul></li></ul>
<ul><li>
Rhythm and blues
<ul><li>
Urban contemporary
</li></ul></li></ul>
.. note::
Categories that have similar ancestors are grouped accordingly. There is no duplication of the ancestor tree.
display_path_as_ul
==================
Inclusion tags
==============
Render the category with ancestors, but no children using the ``categories/ul_tree.html`` template.
``display_path_as_ul``
----------------------
Example:
**Template Rendered:** ``categories/ul_tree.html``
**Syntax 1:** ``{% display_path_as_ul <category_obj> %}``
**Syntax 2:** ``{% display_path_as_ul <path_string>[ using="app.Model"] %}``
Render the category with ancestors, but no children.
Pass either an object that subclasses :py:class:`CategoryBase` or a path string for the category. Add ``using="app.Model"`` to specify which model when using a path string. The default model used is :py:class:`Category`.
**Example, using Category model:**
.. code-block:: django
{% display_path_as_ul "/Grandparent/Parent" %}
or
**Example, using custom model:**
.. code-block:: django
{% display_path_as_ul "/Grandparent/Parent" using="coolapp.MusicGenre" %}
**Example, using an object:**
.. code-block:: django
@ -37,51 +150,39 @@ Returns:
.. code-block:: html
<ul>
<li><a href="/categories/">Top</a>
<ul>
<li><a href="/categories/grandparent/">Grandparent</a></li>
</ul>
</li>
</ul>
<ul>
<li><a href="/categories/">Top</a>
<ul>
<li><a href="/categories/grandparent/">Grandparent</a></li>
</ul>
</li>
</ul>
get_category_drilldown
======================
``display_drilldown_as_ul``
---------------------------
Retrieves the specified category, its ancestors and its immediate children
as an iterable.
**Template rendered:** ``categories/ul_tree.html``
Example:
**Syntax 1:** ``{% display_drilldown_as_ul category_obj %}``
.. code-block:: django
**Syntax 2:** ``{% display_drilldown_as_ul "/Grandparent/Parent" [using="app.Model"] %}``
{% get_category_drilldown "/Grandparent/Parent" as family %}
Render the category with ancestors and children.
or
.. code-block:: django
{% get_category_drilldown category_obj as family %}
Sets ``family`` to::
[Grandparent, Parent, Child 1, Child 2, Child n]
display_drilldown_as_ul
=======================
Render the category with ancestors and children using the
``categories/ul_tree.html`` template.
Example:
**Example, using Category model:**
.. code-block:: django
{% display_drilldown_as_ul "/Grandparent/Parent" %}
or:
**Example, using custom model:**
.. code-block:: django
{% display_drilldown_as_ul "/Grandparent/Parent" using="coolapp.MusicGenre" %}
**Example, using an object:**
.. code-block:: django
@ -110,18 +211,30 @@ Returns:
</ul>
breadcrumbs tag
===============
``breadcrumbs tag``
-------------------
Render breadcrumbs, using the ``categories/breadcrumbs.html`` template, using the optional ``separator`` argument.
**Template rendered:** ``categories/breadcrumbs.html``
Example:
**Syntax 1:** ``{% breadcrumbs category_obj [separator=" :: "] %}``
**Syntax 2:** ``{% breadcrumbs "/Grandparent/Parent" [separator=" :: "] [using="app.Model"] %}``
Render breadcrumbs for the given path using ``::`` or the given separator.
**Example using Category model:**
.. code-block:: django
{% breadcrumbs "/Grandparent/Parent" %}
or:
**Example using a custom model:**
.. code-block:: django
{% breadcrumbs "/Grandparent/Parent" using="coolapp.MusicGenre" %}
**Example using an object:**
.. code-block:: django
@ -133,14 +246,103 @@ Returns:
<a href="/categories/grandparent/">Grandparent</a> / Parent
You can alter the separator used in the template by adding a string argument to be the separator:
You can alter the separator used in the template by adding a separator argument:
.. code-block:: django
{% breadcrumbs category_obj "::" %}
{% breadcrumbs category_obj separator=" &gt; " %}
Returns:
.. code-block:: html
<a href="/categories/grandparent/">Grandparent</a> :: Parent
<a href="/categories/grandparent/">Grandparent</a> &gt; Parent
Template Tags
=============
``get_top_level_categories``
----------------------------
Retrieves an alphabetical list of all the categories that have no parents.
Syntax:
.. code-block:: django
{% get_top_level_categories [using "app.Model"] as categories %}
Returns an list of categories ``[<category>, <category>, <category, ...]``
``get_category_drilldown``
--------------------------
**Syntax 1:** ``{% get_category_drilldown <path_string> [using "app.Model"] as <varname> %}``
**Syntax 2:** ``{% get_category_drilldown <object> as <varname> %}``
Retrieves the specified category, its ancestors and its immediate children as an iterable. Syntax 1 allows for the retrieval of the category object via a slash-delimited path. The optional ``using "app.Model"`` allows you to specify from which model to retrieve the object.
Example:
.. code-block:: django
{% get_category_drilldown "/Grandparent/Parent" using "family.Member" as family %}
The second syntax uses an instance of any object that subclasses :py:class:`CategoryBase`
.. code-block:: django
{% get_category_drilldown category_obj as family %}
Both examples sets ``family`` to::
[Grandparent, Parent, Child 1, Child 2, Child n]
``recursetree``
---------------
This tag renders a section of your template recursively for each node in your
tree.
For example:
.. code-block:: django
<ul class="root">
{% recursetree nodes %}
<li>
{{ node.name }}
{% if not node.is_leaf_node %}
<ul class="children">
{{ children }}
</ul>
{% endif %}
</li>
{% endrecursetree %}
</ul>
Note the special variables ``node`` and ``children``.
These are magically inserted into your context while you're inside the
``recursetree`` tag.
``node`` is an instance of your MPTT model.
``children`` : This variable holds the rendered HTML for the children of
``node``.
.. note::
If you already have variables called ``node`` or ``children`` in your
template, and you need to access them inside the ``recursetree`` block,
you'll need to alias them to some other name first:
.. code-block:: django
{% with node as friendly_node %}
{% recursetree nodes %}
{{ node.name }} is friends with {{ friendly_node.name }}
{{ children }}
{% endrecursetree %}
{% endwith %}

View file

@ -18,7 +18,7 @@ For many cases, you want a simple user-managed lookup table. You can do this wit
#. Create a subclass of CategoryBaseAdmin.
.. literalinclude:: code_examples/custom_categories1.py
.. literalinclude:: code_examples/custom_categories2.py
:linenos:
#. Register your model and custom model admin class.

View file

@ -6,27 +6,17 @@ Django Categories grew out of our need to provide a basic hierarchical taxonomy
As a news site, our stories, photos, and other content get divided into "sections" and we wanted all the apps to use the same set of sections. As our needs grew, the Django Categories grew in the functionality it gave to category handling within web pages.
New in 1.0
New in 1.1
==========
**Abstract Base Class for generic hierarchical category models**
When you want a multiple types of categories and don't want them all part of the same model, you can now easily create new models by subclassing ``CategoryBase``. You can also add additional metadata as necessary.
Your model's can subclass ``CategoryBaseAdminForm`` and ``CategoryBaseAdmin`` to get the hierarchical management in the admin.
See the docs for more information.
* Fixed a cosmetic bug in the Django 1.4 admin. Action checkboxes now only appear once.
**Increased the default caching time on views**
The default setting for ``CACHE_VIEW_LENGTH`` was ``0``, which means it would tell the browser to *never* cache the page. It is now ``600``, which is the default for `CACHE_MIDDLEWARE_SECONDS <https://docs.djangoproject.com/en/1.3/ref/settings/#cache-middleware-seconds>`_
* Template tags are refactored to allow easy use of any model derived from ``CategoryBase``.
**Updated for use with Django-MPTT 0.5**
Just a few tweaks.
* Improved test suite.
**Initial compatibility with Django 1.4**
More is coming, but at least it works.
* Improved some of the documentation.
**Slug transliteration for non-ASCII characters**
A new setting, ``SLUG_TRANSLITERATOR``, allows you to specify a function for converting the non-ASCII characters to ASCII characters before the slugification. Works great with `Unidecode <http://pypi.python.org/pypi/Unidecode>`_.
Contents

View file

@ -1,33 +1,146 @@
=============
Template Tags
=============
=========================
Template tags and filters
=========================
get_top_level_categories
========================
.. contents::
:depth: 2
:local:
:backlinks: top
Retrieves an alphabetical list of all the categories that have no parents.
Syntax:
Filters
=======
``category_path``
-----------------
**Optional Parameter:** separator string. *Default:* ``" :: "``
Creates a path represented by a categories by joining the items with a separator.
Each path item will be coerced to unicode, so you can pass a list of category instances, if required.
**Example using a list of categories:**
.. code-block:: django
{% get_top_level_categories as categories %}
{{ some_list|category_path }}
Returns an list of categories ``[<category>, <category>, <category, ...]``
If ``some_list`` is ``[ <Category: Country>, <Category: Country pop>, <Category: Urban Cowboy>]`` the result will be::
Country :: Country pop :: Urban Cowboy
**Example using a category node and optional separator parameter:**
.. code-block:: django
{{ some_node.get_ancestors|category_path:" > " }}
If ``some_node`` was category "Urban Cowboy", the result will be::
Country > Country pop > Urban Cowboy
.. _tree_info:
``tree_info``
-------------
**Optional Parameter:** ``"ancestors"``
Given a list of categories, it iterates over the list, generating a tuple of the current category and a dict containing information about the tree structure around it, with the following keys:
``'new_level'``
``True`` if the current item is the start of a new level in the tree, ``False`` otherwise.
``'closed_levels'``
A list of levels which end after the current item. This will be an empty list if the next category's level is the same as or greater than the level of the current item.
Provide the optional argument, ``"ancestors"``, to add a list of unicode representations of the ancestors of the current category, in descending order (root node first, immediate parent last), under the key 'ancestors'.
For example: given the sample tree below, the contents of the list which would be available under the 'ancestors' key are given on the right::
Country -> []
Country pop -> [u'Country pop']
Urban Cowboy -> [u'Country', u'Country pop']
Using this filter with unpacking in a {% for %} tag, you should have enough information about the tree structure to create a hierarchical representation of the tree.
.. code-block:: django
{% for node,structure in objects|tree_info %}
{% if structure.new_level %}<ul><li>{% else %}</li><li>{% endif %}
{{ node.name }}
{% for level in structure.closed_levels %}</li></ul>{% endfor %}
{% endfor %}
``tree_queryset``
-----------------
Convert a regular category :py:class:`QuerySet` into a new, ordered :py:class:`QuerySet` that includes the categories selected and their ancestors.
This is especially helpful when you have a subset of categories and want to show the hierarchy for all the items.
For example, if we add it to the example for :ref:`tree_info`:
.. code-block:: django
{% for node,structure in objects|tree_queryset|tree_info %}
{% if structure.new_level %}<ul><li>{% else %}</li><li>{% endif %}
{{ node.name }}
{% for level in structure.closed_levels %}</li></ul>{% endfor %}
{% endfor %}
A list of unrelated categories such as ``[<Category: Urban cowboy>, <Category: Urban comtemporary>]``, the above template example will output the two categories and their ancestors:
.. code-block:: html
<ul><li>
Country
<ul><li>
Country pop
<ul><li>
Urban cowboy
</li></ul></li></ul></li></ul>
<ul><li>
Rhythm and blues
<ul><li>
Urban contemporary
</li></ul></li></ul>
.. note::
Categories that have similar ancestors are grouped accordingly. There is no duplication of the ancestor tree.
display_path_as_ul
==================
Inclusion tags
==============
Render the category with ancestors, but no children using the ``categories/ul_tree.html`` template.
``display_path_as_ul``
----------------------
Example:
**Template Rendered:** ``categories/ul_tree.html``
**Syntax 1:** ``{% display_path_as_ul <category_obj> %}``
**Syntax 2:** ``{% display_path_as_ul <path_string>[ using="app.Model"] %}``
Render the category with ancestors, but no children.
Pass either an object that subclasses :py:class:`CategoryBase` or a path string for the category. Add ``using="app.Model"`` to specify which model when using a path string. The default model used is :py:class:`Category`.
**Example, using Category model:**
.. code-block:: django
{% display_path_as_ul "/Grandparent/Parent" %}
or
**Example, using custom model:**
.. code-block:: django
{% display_path_as_ul "/Grandparent/Parent" using="coolapp.MusicGenre" %}
**Example, using an object:**
.. code-block:: django
@ -37,51 +150,39 @@ Returns:
.. code-block:: html
<ul>
<li><a href="/categories/">Top</a>
<ul>
<li><a href="/categories/grandparent/">Grandparent</a></li>
</ul>
</li>
</ul>
<ul>
<li><a href="/categories/">Top</a>
<ul>
<li><a href="/categories/grandparent/">Grandparent</a></li>
</ul>
</li>
</ul>
get_category_drilldown
======================
``display_drilldown_as_ul``
---------------------------
Retrieves the specified category, its ancestors and its immediate children
as an iterable.
**Template rendered:** ``categories/ul_tree.html``
Example:
**Syntax 1:** ``{% display_drilldown_as_ul category_obj %}``
.. code-block:: django
**Syntax 2:** ``{% display_drilldown_as_ul "/Grandparent/Parent" [using="app.Model"] %}``
{% get_category_drilldown "/Grandparent/Parent" as family %}
Render the category with ancestors and children.
or
.. code-block:: django
{% get_category_drilldown category_obj as family %}
Sets ``family`` to::
[Grandparent, Parent, Child 1, Child 2, Child n]
display_drilldown_as_ul
=======================
Render the category with ancestors and children using the
``categories/ul_tree.html`` template.
Example:
**Example, using Category model:**
.. code-block:: django
{% display_drilldown_as_ul "/Grandparent/Parent" %}
or:
**Example, using custom model:**
.. code-block:: django
{% display_drilldown_as_ul "/Grandparent/Parent" using="coolapp.MusicGenre" %}
**Example, using an object:**
.. code-block:: django
@ -110,18 +211,30 @@ Returns:
</ul>
breadcrumbs tag
===============
``breadcrumbs tag``
-------------------
Render breadcrumbs, using the ``categories/breadcrumbs.html`` template, using the optional ``separator`` argument.
**Template rendered:** ``categories/breadcrumbs.html``
Example:
**Syntax 1:** ``{% breadcrumbs category_obj [separator=" :: "] %}``
**Syntax 2:** ``{% breadcrumbs "/Grandparent/Parent" [separator=" :: "] [using="app.Model"] %}``
Render breadcrumbs for the given path using ``::`` or the given separator.
**Example using Category model:**
.. code-block:: django
{% breadcrumbs "/Grandparent/Parent" %}
or:
**Example using a custom model:**
.. code-block:: django
{% breadcrumbs "/Grandparent/Parent" using="coolapp.MusicGenre" %}
**Example using an object:**
.. code-block:: django
@ -133,14 +246,103 @@ Returns:
<a href="/categories/grandparent/">Grandparent</a> / Parent
You can alter the separator used in the template by adding a string argument to be the separator:
You can alter the separator used in the template by adding a separator argument:
.. code-block:: django
{% breadcrumbs category_obj "::" %}
{% breadcrumbs category_obj separator=" &gt; " %}
Returns:
.. code-block:: html
<a href="/categories/grandparent/">Grandparent</a> :: Parent
<a href="/categories/grandparent/">Grandparent</a> &gt; Parent
Template Tags
=============
``get_top_level_categories``
----------------------------
Retrieves an alphabetical list of all the categories that have no parents.
Syntax:
.. code-block:: django
{% get_top_level_categories [using "app.Model"] as categories %}
Returns an list of categories ``[<category>, <category>, <category, ...]``
``get_category_drilldown``
--------------------------
**Syntax 1:** ``{% get_category_drilldown <path_string> [using "app.Model"] as <varname> %}``
**Syntax 2:** ``{% get_category_drilldown <object> as <varname> %}``
Retrieves the specified category, its ancestors and its immediate children as an iterable. Syntax 1 allows for the retrieval of the category object via a slash-delimited path. The optional ``using "app.Model"`` allows you to specify from which model to retrieve the object.
Example:
.. code-block:: django
{% get_category_drilldown "/Grandparent/Parent" using "family.Member" as family %}
The second syntax uses an instance of any object that subclasses :py:class:`CategoryBase`
.. code-block:: django
{% get_category_drilldown category_obj as family %}
Both examples sets ``family`` to::
[Grandparent, Parent, Child 1, Child 2, Child n]
``recursetree``
---------------
This tag renders a section of your template recursively for each node in your
tree.
For example:
.. code-block:: django
<ul class="root">
{% recursetree nodes %}
<li>
{{ node.name }}
{% if not node.is_leaf_node %}
<ul class="children">
{{ children }}
</ul>
{% endif %}
</li>
{% endrecursetree %}
</ul>
Note the special variables ``node`` and ``children``.
These are magically inserted into your context while you're inside the
``recursetree`` tag.
``node`` is an instance of your MPTT model.
``children`` : This variable holds the rendered HTML for the children of
``node``.
.. note::
If you already have variables called ``node`` or ``children`` in your
template, and you need to access them inside the ``recursetree`` block,
you'll need to alias them to some other name first:
.. code-block:: django
{% with node as friendly_node %}
{% recursetree nodes %}
{{ node.name }} is friends with {{ friendly_node.name }}
{{ children }}
{% endrecursetree %}
{% endwith %}

View file

@ -79,14 +79,6 @@ div.sphinxsidebar input {
font-size: 1em;
}
div.sphinxsidebar input[type="text"] {
width: 170px;
}
div.sphinxsidebar input[type="submit"] {
width: 30px;
}
img {
border: 0;
}
@ -244,6 +236,7 @@ img.align-center, .figure.align-center, object.align-center {
}
.align-center {
clear: both;
text-align: center;
}
@ -447,11 +440,6 @@ dl.glossary dt {
font-style: oblique;
}
abbr, acronym {
border-bottom: dotted 1px;
cursor: help;
}
/* -- code displays --------------------------------------------------------- */
pre {
@ -537,4 +525,4 @@ span.eqno {
#top-link {
display: none;
}
}
}

View file

@ -62,7 +62,7 @@ div.clearer {
.headerButton a:hover {
color: white;
background-color: #787878;
}
li#toc_button {
@ -121,7 +121,7 @@ right:0;
top: 84px;
bottom: 19px;
left: 0px;
width: 229px;
width: 229px;
background-color: #E4EBF7;
border-right: 1px solid #ACACAC;
border-top: 1px solid #2B334F;
@ -362,7 +362,7 @@ p.topic-title {
border:1px solid #111111;
margin:30px;
}
.admonition p {
.admonition p {
font: 12px 'Lucida Grande', Geneva, Helvetica, Arial, sans-serif;
margin-top: 7px;
margin-bottom: 0px;
@ -411,7 +411,7 @@ table.docutils td, table.docutils th {
table.docutils th {
font-weight: bold;
}
/* This alternates colors in up to six table rows (light blue for odd, white for even)*/
/* This alternates colors in up to six table rows (light blue for odd, white for even)*/
.docutils tr {
background: #F0F5F9;
}
@ -453,6 +453,7 @@ th {
dl {
margin-bottom: 15px;
font-size: 12px;
}
dd p {
@ -544,7 +545,7 @@ td.linenos pre {
}
td.code {
}
table.highlighttable {
@ -562,7 +563,6 @@ table.highlighttable td.linenos {
}
tt {
font-family:"Bitstream Vera Sans Mono",Monaco,"Lucida Console",Courier,Consolas,monospace;
}
tt.descname {
@ -643,7 +643,7 @@ dl.class dd dl.method dt {
padding: 3px;
background-color: #e9e9e9;
border-top: none;
}
dl.function dt {
@ -659,7 +659,7 @@ margin:0 0 0 30px;
padding:0 0 12px 6px;
}
#docstitle {
height: 36px;
height: 36px;
background-image: url(header_sm_mid.png);
left: 0;
top: 0;

View file

@ -2,7 +2,7 @@
* doctools.js
* ~~~~~~~~~~~
*
* Sphinx JavaScript utilities for all documentation.
* Sphinx JavaScript utilties for all documentation.
*
* :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details.
@ -185,9 +185,9 @@ var Documentation = {
body.highlightText(this.toLowerCase(), 'highlighted');
});
}, 10);
$('<p class="highlight-link"><a href="javascript:Documentation.' +
'hideSearchWords()">' + _('Hide Search Matches') + '</a></p>')
.appendTo($('#searchbox'));
$('<li class="highlight-link"><a href="javascript:Documentation.' +
'hideSearchWords()">' + _('Hide Search Matches') + '</a></li>')
.appendTo($('.sidebar .this-page-menu'));
}
},
@ -213,7 +213,7 @@ var Documentation = {
* helper function to hide the search marks again
*/
hideSearchWords : function() {
$('#searchbox .highlight-link').fadeOut(300);
$('.sidebar .this-page-menu li.highlight-link').fadeOut(300);
$('span.highlighted').removeClass('highlighted');
},

View file

@ -1,6 +1,6 @@
/*
* searchtools.js_t
* ~~~~~~~~~~~~~~~~
* searchtools.js
* ~~~~~~~~~~~~~~
*
* Sphinx JavaScript utilties for the full-text search.
*
@ -36,11 +36,10 @@ jQuery.makeSearchSummary = function(text, keywords, hlwords) {
return rv;
}
/**
* Porter Stemmer
*/
var Stemmer = function() {
var PorterStemmer = function() {
var step2list = {
ational: 'ate',
@ -301,20 +300,20 @@ var Search = {
},
query : function(query) {
var stopwords = ["and","then","into","it","as","are","in","if","for","no","there","their","was","is","be","to","that","but","they","not","such","with","by","a","on","these","of","will","this","near","the","or","at"];
var stopwords = ['and', 'then', 'into', 'it', 'as', 'are', 'in',
'if', 'for', 'no', 'there', 'their', 'was', 'is',
'be', 'to', 'that', 'but', 'they', 'not', 'such',
'with', 'by', 'a', 'on', 'these', 'of', 'will',
'this', 'near', 'the', 'or', 'at'];
// Stem the searchterms and add them to the correct list
var stemmer = new Stemmer();
// stem the searchterms and add them to the correct list
var stemmer = new PorterStemmer();
var searchterms = [];
var excluded = [];
var hlterms = [];
var tmp = query.split(/\s+/);
var objectterms = [];
var object = (tmp.length == 1) ? tmp[0].toLowerCase() : null;
for (var i = 0; i < tmp.length; i++) {
if (tmp[i] != "") {
objectterms.push(tmp[i].toLowerCase());
}
if ($u.indexOf(stopwords, tmp[i]) != -1 || tmp[i].match(/^\d+$/) ||
tmp[i] == "") {
// skip this "word"
@ -345,6 +344,9 @@ var Search = {
var filenames = this._index.filenames;
var titles = this._index.titles;
var terms = this._index.terms;
var objects = this._index.objects;
var objtypes = this._index.objtypes;
var objnames = this._index.objnames;
var fileMap = {};
var files = null;
// different result priorities
@ -355,19 +357,40 @@ var Search = {
$('#search-progress').empty();
// lookup as object
for (var i = 0; i < objectterms.length; i++) {
var others = [].concat(objectterms.slice(0,i),
objectterms.slice(i+1, objectterms.length))
var results = this.performObjectSearch(objectterms[i], others);
// Assume first word is most likely to be the object,
// other words more likely to be in description.
// Therefore put matches for earlier words first.
// (Results are eventually used in reverse order).
objectResults = results[0].concat(objectResults);
importantResults = results[1].concat(importantResults);
unimportantResults = results[2].concat(unimportantResults);
if (object != null) {
for (var prefix in objects) {
for (var name in objects[prefix]) {
var fullname = (prefix ? prefix + '.' : '') + name;
if (fullname.toLowerCase().indexOf(object) > -1) {
match = objects[prefix][name];
descr = objnames[match[1]] + _(', in ') + titles[match[0]];
// XXX the generated anchors are not generally correct
// XXX there may be custom prefixes
result = [filenames[match[0]], fullname, '#'+fullname, descr];
switch (match[2]) {
case 1: objectResults.push(result); break;
case 0: importantResults.push(result); break;
case 2: unimportantResults.push(result); break;
}
}
}
}
}
// sort results descending
objectResults.sort(function(a, b) {
return (a[1] > b[1]) ? -1 : ((a[1] < b[1]) ? 1 : 0);
});
importantResults.sort(function(a, b) {
return (a[1] > b[1]) ? -1 : ((a[1] < b[1]) ? 1 : 0);
});
unimportantResults.sort(function(a, b) {
return (a[1] > b[1]) ? -1 : ((a[1] < b[1]) ? 1 : 0);
});
// perform the search on the required terms
for (var i = 0; i < searchterms.length; i++) {
var word = searchterms[i];
@ -466,7 +489,7 @@ var Search = {
listItem.slideDown(5, function() {
displayNextItem();
});
}, "text");
});
} else {
// no source available, just display title
Search.output.append(listItem);
@ -487,74 +510,9 @@ var Search = {
}
}
displayNextItem();
},
performObjectSearch : function(object, otherterms) {
var filenames = this._index.filenames;
var objects = this._index.objects;
var objnames = this._index.objnames;
var titles = this._index.titles;
var importantResults = [];
var objectResults = [];
var unimportantResults = [];
for (var prefix in objects) {
for (var name in objects[prefix]) {
var fullname = (prefix ? prefix + '.' : '') + name;
if (fullname.toLowerCase().indexOf(object) > -1) {
var match = objects[prefix][name];
var objname = objnames[match[1]][2];
var title = titles[match[0]];
// If more than one term searched for, we require other words to be
// found in the name/title/description
if (otherterms.length > 0) {
var haystack = (prefix + ' ' + name + ' ' +
objname + ' ' + title).toLowerCase();
var allfound = true;
for (var i = 0; i < otherterms.length; i++) {
if (haystack.indexOf(otherterms[i]) == -1) {
allfound = false;
break;
}
}
if (!allfound) {
continue;
}
}
var descr = objname + _(', in ') + title;
anchor = match[3];
if (anchor == '')
anchor = fullname;
else if (anchor == '-')
anchor = objnames[match[1]][1] + '-' + fullname;
result = [filenames[match[0]], fullname, '#'+anchor, descr];
switch (match[2]) {
case 1: objectResults.push(result); break;
case 0: importantResults.push(result); break;
case 2: unimportantResults.push(result); break;
}
}
}
}
// sort results descending
objectResults.sort(function(a, b) {
return (a[1] > b[1]) ? -1 : ((a[1] < b[1]) ? 1 : 0);
});
importantResults.sort(function(a, b) {
return (a[1] > b[1]) ? -1 : ((a[1] < b[1]) ? 1 : 0);
});
unimportantResults.sort(function(a, b) {
return (a[1] > b[1]) ? -1 : ((a[1] < b[1]) ? 1 : 0);
});
return [importantResults, objectResults, unimportantResults]
}
}
$(document).ready(function() {
Search.init();
});
});

View file

@ -29,9 +29,6 @@ $(function() {
var sidebar = $('.sphinxsidebar');
var sidebarwrapper = $('.sphinxsidebarwrapper');
// for some reason, the document has no sidebar; do not run into errors
if (!sidebar.length) return;
// original margin-left of the bodywrapper and width of the sidebar
// with the sidebar expanded
var bw_margin_expanded = bodywrapper.css('margin-left');

View file

@ -1,10 +1,3 @@
// Underscore.js 0.5.5
// (c) 2009 Jeremy Ashkenas, DocumentCloud Inc.
// Underscore is freely distributable under the terms of the MIT license.
// Portions of Underscore are inspired by or borrowed from Prototype.js,
// Oliver Steele's Functional, and John Resig's Micro-Templating.
// For all details and documentation:
// http://documentcloud.github.com/underscore/
(function(){var j=this,n=j._,i=function(a){this._wrapped=a},m=typeof StopIteration!=="undefined"?StopIteration:"__break__",b=j._=function(a){return new i(a)};if(typeof exports!=="undefined")exports._=b;var k=Array.prototype.slice,o=Array.prototype.unshift,p=Object.prototype.toString,q=Object.prototype.hasOwnProperty,r=Object.prototype.propertyIsEnumerable;b.VERSION="0.5.5";b.each=function(a,c,d){try{if(a.forEach)a.forEach(c,d);else if(b.isArray(a)||b.isArguments(a))for(var e=0,f=a.length;e<f;e++)c.call(d,
a[e],e,a);else{var g=b.keys(a);f=g.length;for(e=0;e<f;e++)c.call(d,a[g[e]],g[e],a)}}catch(h){if(h!=m)throw h;}return a};b.map=function(a,c,d){if(a&&b.isFunction(a.map))return a.map(c,d);var e=[];b.each(a,function(f,g,h){e.push(c.call(d,f,g,h))});return e};b.reduce=function(a,c,d,e){if(a&&b.isFunction(a.reduce))return a.reduce(b.bind(d,e),c);b.each(a,function(f,g,h){c=d.call(e,c,f,g,h)});return c};b.reduceRight=function(a,c,d,e){if(a&&b.isFunction(a.reduceRight))return a.reduceRight(b.bind(d,e),c);
var f=b.clone(b.toArray(a)).reverse();b.each(f,function(g,h){c=d.call(e,c,g,h,a)});return c};b.detect=function(a,c,d){var e;b.each(a,function(f,g,h){if(c.call(d,f,g,h)){e=f;b.breakLoop()}});return e};b.select=function(a,c,d){if(a&&b.isFunction(a.filter))return a.filter(c,d);var e=[];b.each(a,function(f,g,h){c.call(d,f,g,h)&&e.push(f)});return e};b.reject=function(a,c,d){var e=[];b.each(a,function(f,g,h){!c.call(d,f,g,h)&&e.push(f)});return e};b.all=function(a,c,d){c=c||b.identity;if(a&&b.isFunction(a.every))return a.every(c,

View file

@ -2,20 +2,17 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Adding the fields to the database &mdash; Django Categories 1.0.5 documentation</title>
<title>Adding the fields to the database &mdash; Django Categories v1.1 documentation</title>
<link rel="stylesheet" href="_static/default.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: '',
VERSION: '1.0.5',
VERSION: '1.1',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true
@ -24,13 +21,13 @@
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/underscore.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<link rel="top" title="Django Categories 1.0.5 documentation" href="index.html" />
<link rel="top" title="Django Categories v1.1 documentation" href="index.html" />
<link rel="next" title="Creating Custom Categories" href="custom_categories.html" />
<link rel="prev" title="Registering Models" href="registering_models.html" />
</head>
<body>
<div id="docstitle">
<p>Django Categories 1.0.5 documentation</p>
<p>Django Categories v1.1 documentation</p>
</div>
<div id="header">
<div id="title"><h1>Adding the fields to the database</h1></div>
@ -116,7 +113,7 @@
<div class="footer">
<p>
&copy; Copyright 2010-2012, Corey Oordt.
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.2.
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.0.7.
</p>
</div>
<div class="clearer"></div>

View file

@ -2,20 +2,17 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Creating Custom Categories &mdash; Django Categories 1.0.5 documentation</title>
<title>Creating Custom Categories &mdash; Django Categories v1.1 documentation</title>
<link rel="stylesheet" href="_static/default.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: '',
VERSION: '1.0.5',
VERSION: '1.1',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true
@ -24,13 +21,13 @@
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/underscore.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<link rel="top" title="Django Categories 1.0.5 documentation" href="index.html" />
<link rel="top" title="Django Categories v1.1 documentation" href="index.html" />
<link rel="next" title="Reference" href="reference/index.html" />
<link rel="prev" title="Adding the fields to the database" href="adding_the_fields.html" />
</head>
<body>
<div id="docstitle">
<p>Django Categories 1.0.5 documentation</p>
<p>Django Categories v1.1 documentation</p>
</div>
<div id="header">
<div id="title"><h1>Creating Custom Categories</h1></div>
@ -122,23 +119,25 @@
</td></tr></table></div>
</li>
<li><p class="first">Create a subclass of CategoryBaseAdmin.</p>
<div class="highlight-python"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4
5
6
7
8
9</pre></div></td><td class="code"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">categories.models</span> <span class="kn">import</span> <span class="n">CategoryBase</span>
<div class="highlight-python"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre> 1
2
3
4
5
6
7
8
9
10</pre></div></td><td class="code"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">django.contrib</span> <span class="kn">import</span> <span class="n">admin</span>
<span class="k">class</span> <span class="nc">SimpleCategory</span><span class="p">(</span><span class="n">CategoryBase</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> A simple of catgorizing example</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">class</span> <span class="nc">Meta</span><span class="p">:</span>
<span class="n">verbose_name_plural</span> <span class="o">=</span> <span class="s">&#39;simple categories&#39;</span>
<span class="kn">from</span> <span class="nn">categories.admin</span> <span class="kn">import</span> <span class="n">CategoryBaseAdmin</span>
<span class="kn">from</span> <span class="nn">.models</span> <span class="kn">import</span> <span class="n">SimpleCategory</span>
<span class="k">class</span> <span class="nc">SimpleCategoryAdmin</span><span class="p">(</span><span class="n">CategoryBaseAdmin</span><span class="p">):</span>
<span class="k">pass</span>
<span class="n">admin</span><span class="o">.</span><span class="n">site</span><span class="o">.</span><span class="n">register</span><span class="p">(</span><span class="n">SimpleCategory</span><span class="p">,</span> <span class="n">SimpleCategoryAdmin</span><span class="p">)</span>
</pre></div>
</td></tr></table></div>
</li>
@ -328,7 +327,7 @@
<div class="footer">
<p>
&copy; Copyright 2010-2012, Corey Oordt.
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.2.
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.0.7.
</p>
</div>
<div class="clearer"></div>

View file

@ -1,23 +1,18 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Index &mdash; Django Categories 1.0.5 documentation</title>
<title>Index &mdash; Django Categories v1.1 documentation</title>
<link rel="stylesheet" href="_static/default.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: '',
VERSION: '1.0.5',
VERSION: '1.1',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true
@ -26,11 +21,11 @@
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/underscore.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<link rel="top" title="Django Categories 1.0.5 documentation" href="index.html" />
<link rel="top" title="Django Categories v1.1 documentation" href="index.html" />
</head>
<body>
<div id="docstitle">
<p>Django Categories 1.0.5 documentation</p>
<p>Django Categories v1.1 documentation</p>
</div>
<div id="header">
<div id="title"><h1>Index</h1></div>
@ -86,167 +81,100 @@
<div class="body">
<h1 id="index">Index</h1>
<h1 id="index">Index</h1>
<div class="genindex-jumpbox">
<a href="#A"><strong>A</strong></a>
| <a href="#C"><strong>C</strong></a>
| <a href="#D"><strong>D</strong></a>
| <a href="#M"><strong>M</strong></a>
| <a href="#N"><strong>N</strong></a>
| <a href="#O"><strong>O</strong></a>
| <a href="#P"><strong>P</strong></a>
| <a href="#R"><strong>R</strong></a>
| <a href="#S"><strong>S</strong></a>
| <a href="#T"><strong>T</strong></a>
</div>
<div class="genindex-jumpbox">
<a href="#A"><strong>A</strong></a> | <a href="#C"><strong>C</strong></a> | <a href="#D"><strong>D</strong></a> | <a href="#M"><strong>M</strong></a> | <a href="#N"><strong>N</strong></a> | <a href="#O"><strong>O</strong></a> | <a href="#P"><strong>P</strong></a> | <a href="#R"><strong>R</strong></a> | <a href="#S"><strong>S</strong></a> | <a href="#T"><strong>T</strong></a>
</div>
<h2 id="A">A</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%" valign="top"><dl>
<dt><a href="reference/models.html#CategoryBase.active">active (CategoryBase attribute)</a>
</dt>
<dt><a href="reference/models.html#Category.alternate_title">alternate_title (Category attribute)</a>
</dt>
</dl></td>
<dt><a href="reference/models.html#CategoryBase.active">active (CategoryBase attribute)</a></dt>
<dt><a href="reference/models.html#Category.alternate_title">alternate_title (Category attribute)</a></dt>
</dl></td>
<td style="width: 33%" valign="top"><dl>
<dt><a href="reference/models.html#Category.alternate_url">alternate_url (Category attribute)</a>
</dt>
</dl></td>
<dt><a href="reference/models.html#Category.alternate_url">alternate_url (Category attribute)</a></dt>
</dl></td>
</tr></table>
<h2 id="C">C</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%" valign="top"><dl>
<dt><a href="reference/models.html#Category">Category (built-in class)</a>
</dt>
</dl></td>
<dt><a href="reference/models.html#Category">Category (built-in class)</a></dt>
</dl></td>
<td style="width: 33%" valign="top"><dl>
<dt><a href="reference/models.html#CategoryBase">CategoryBase (built-in class)</a>
</dt>
</dl></td>
<dt><a href="reference/models.html#CategoryBase">CategoryBase (built-in class)</a></dt>
</dl></td>
</tr></table>
<h2 id="D">D</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%" valign="top"><dl>
<dt><a href="reference/models.html#Category.description">description (Category attribute)</a>
</dt>
</dl></td>
<dt><a href="reference/models.html#Category.description">description (Category attribute)</a></dt>
</dl></td>
</tr></table>
<h2 id="M">M</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%" valign="top"><dl>
<dt><a href="reference/models.html#Category.meta_extra">meta_extra (Category attribute)</a>
</dt>
</dl></td>
<dt><a href="reference/models.html#Category.meta_extra">meta_extra (Category attribute)</a></dt>
</dl></td>
<td style="width: 33%" valign="top"><dl>
<dt><a href="reference/models.html#Category.meta_keywords">meta_keywords (Category attribute)</a>
</dt>
</dl></td>
<dt><a href="reference/models.html#Category.meta_keywords">meta_keywords (Category attribute)</a></dt>
</dl></td>
</tr></table>
<h2 id="N">N</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%" valign="top"><dl>
<dt><a href="reference/models.html#CategoryBase.name">name (CategoryBase attribute)</a>
</dt>
</dl></td>
<dt><a href="reference/models.html#CategoryBase.name">name (CategoryBase attribute)</a></dt>
</dl></td>
</tr></table>
<h2 id="O">O</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%" valign="top"><dl>
<dt><a href="reference/models.html#CategoryBase.objects">objects (CategoryBase attribute)</a>
</dt>
</dl></td>
<dt><a href="reference/models.html#CategoryBase.objects">objects (CategoryBase attribute)</a></dt>
</dl></td>
<td style="width: 33%" valign="top"><dl>
<dt><a href="reference/models.html#Category.order">order (Category attribute)</a>
</dt>
</dl></td>
<dt><a href="reference/models.html#Category.order">order (Category attribute)</a></dt>
</dl></td>
</tr></table>
<h2 id="P">P</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%" valign="top"><dl>
<dt><a href="reference/models.html#CategoryBase.parent">parent (CategoryBase attribute)</a>
</dt>
</dl></td>
<dt><a href="reference/models.html#CategoryBase.parent">parent (CategoryBase attribute)</a></dt>
</dl></td>
</tr></table>
<h2 id="R">R</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%" valign="top"><dl>
<dt><a href="registering_models.html#register_fk">register_fk() (built-in function)</a>
</dt>
</dl></td>
<dt><a href="registering_models.html#register_fk">register_fk() (built-in function)</a></dt>
</dl></td>
<td style="width: 33%" valign="top"><dl>
<dt><a href="registering_models.html#register_m2m">register_m2m() (built-in function)</a>
</dt>
</dl></td>
<dt><a href="registering_models.html#register_m2m">register_m2m() (built-in function)</a></dt>
</dl></td>
</tr></table>
<h2 id="S">S</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%" valign="top"><dl>
<dt><a href="reference/models.html#CategoryBase.slug">slug (CategoryBase attribute)</a>
</dt>
</dl></td>
<dt><a href="reference/models.html#CategoryBase.slug">slug (CategoryBase attribute)</a></dt>
</dl></td>
</tr></table>
<h2 id="T">T</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%" valign="top"><dl>
<dt><a href="reference/models.html#Category.thumbnail">thumbnail (Category attribute)</a>
</dt>
<dt><a href="reference/models.html#Category.thumbnail_height">thumbnail_height (Category attribute)</a>
</dt>
</dl></td>
<dt><a href="reference/models.html#Category.thumbnail">thumbnail (Category attribute)</a></dt>
<dt><a href="reference/models.html#Category.thumbnail_height">thumbnail_height (Category attribute)</a></dt>
</dl></td>
<td style="width: 33%" valign="top"><dl>
<dt><a href="reference/models.html#Category.thumbnail_width">thumbnail_width (Category attribute)</a>
</dt>
<dt><a href="reference/models.html#CategoryBase.tree">tree (CategoryBase attribute)</a>
</dt>
</dl></td>
<dt><a href="reference/models.html#Category.thumbnail_width">thumbnail_width (Category attribute)</a></dt>
<dt><a href="reference/models.html#CategoryBase.tree">tree (CategoryBase attribute)</a></dt>
</dl></td>
</tr></table>
@ -257,7 +185,7 @@
<div class="footer">
<p>
&copy; Copyright 2010-2012, Corey Oordt.
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.2.
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.0.7.
</p>
</div>
<div class="clearer"></div>

View file

@ -2,20 +2,17 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Getting Started &mdash; Django Categories 1.0.5 documentation</title>
<title>Getting Started &mdash; Django Categories v1.1 documentation</title>
<link rel="stylesheet" href="_static/default.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: '',
VERSION: '1.0.5',
VERSION: '1.1',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true
@ -24,13 +21,13 @@
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/underscore.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<link rel="top" title="Django Categories 1.0.5 documentation" href="index.html" />
<link rel="top" title="Django Categories v1.1 documentation" href="index.html" />
<link rel="next" title="Using categories in templates" href="usage.html" />
<link rel="prev" title="Installation" href="installation.html" />
</head>
<body>
<div id="docstitle">
<p>Django Categories 1.0.5 documentation</p>
<p>Django Categories v1.1 documentation</p>
</div>
<div id="header">
<div id="title"><h1>Getting Started</h1></div>
@ -155,7 +152,7 @@ Subject 2
<div class="footer">
<p>
&copy; Copyright 2010-2012, Corey Oordt.
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.2.
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.0.7.
</p>
</div>
<div class="clearer"></div>

View file

@ -2,20 +2,17 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Django Categories v 1.0 &mdash; Django Categories 1.0.5 documentation</title>
<title>Django Categories v 1.1 &mdash; Django Categories v1.1 documentation</title>
<link rel="stylesheet" href="_static/default.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: '',
VERSION: '1.0.5',
VERSION: '1.1',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true
@ -24,15 +21,15 @@
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/underscore.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<link rel="top" title="Django Categories 1.0.5 documentation" href="#" />
<link rel="top" title="Django Categories v1.1 documentation" href="#" />
<link rel="next" title="Installation" href="installation.html" />
</head>
<body>
<div id="docstitle">
<p>Django Categories 1.0.5 documentation</p>
<p>Django Categories v1.1 documentation</p>
</div>
<div id="header">
<div id="title"><h1>Django Categories v 1.0</h1></div>
<div id="title"><h1>Django Categories v 1.1</h1></div>
<ul id="headerButtons">
<li id="toc_button"><div class="headerButton"><a href="#">Table of Contents</a></div></li>
<li id="page_buttons">
@ -88,26 +85,17 @@
<div class="body">
<div class="section" id="django-categories-v-version">
<h1>Django Categories v 1.0<a class="headerlink" href="#django-categories-v-version" title="Permalink to this headline"></a></h1>
<h1>Django Categories v 1.1<a class="headerlink" href="#django-categories-v-version" title="Permalink to this headline"></a></h1>
<p>Django Categories grew out of our need to provide a basic hierarchical taxonomy management system that multiple applications could use independently or in concert.</p>
<p>As a news site, our stories, photos, and other content get divided into &#8220;sections&#8221; and we wanted all the apps to use the same set of sections. As our needs grew, the Django Categories grew in the functionality it gave to category handling within web pages.</p>
<div class="section" id="new-in-1-0">
<h2>New in 1.0<a class="headerlink" href="#new-in-1-0" title="Permalink to this headline"></a></h2>
<dl class="docutils">
<dt><strong>Abstract Base Class for generic hierarchical category models</strong></dt>
<dd><p class="first">When you want a multiple types of categories and don&#8217;t want them all part of the same model, you can now easily create new models by subclassing <tt class="docutils literal"><span class="pre">CategoryBase</span></tt>. You can also add additional metadata as necessary.</p>
<p>Your model&#8217;s can subclass <tt class="docutils literal"><span class="pre">CategoryBaseAdminForm</span></tt> and <tt class="docutils literal"><span class="pre">CategoryBaseAdmin</span></tt> to get the hierarchical management in the admin.</p>
<p class="last">See the docs for more information.</p>
</dd>
<dt><strong>Increased the default caching time on views</strong></dt>
<dd>The default setting for <tt class="docutils literal"><span class="pre">CACHE_VIEW_LENGTH</span></tt> was <tt class="docutils literal"><span class="pre">0</span></tt>, which means it would tell the browser to <em>never</em> cache the page. It is now <tt class="docutils literal"><span class="pre">600</span></tt>, which is the default for <a class="reference external" href="https://docs.djangoproject.com/en/1.3/ref/settings/#cache-middleware-seconds">CACHE_MIDDLEWARE_SECONDS</a></dd>
<dt><strong>Updated for use with Django-MPTT 0.5</strong></dt>
<dd>Just a few tweaks.</dd>
<dt><strong>Initial compatibility with Django 1.4</strong></dt>
<dd>More is coming, but at least it works.</dd>
<dt><strong>Slug transliteration for non-ASCII characters</strong></dt>
<dd>A new setting, <tt class="docutils literal"><span class="pre">SLUG_TRANSLITERATOR</span></tt>, allows you to specify a function for converting the non-ASCII characters to ASCII characters before the slugification. Works great with <a class="reference external" href="http://pypi.python.org/pypi/Unidecode">Unidecode</a>.</dd>
</dl>
<div class="section" id="new-in-1-1">
<h2>New in 1.1<a class="headerlink" href="#new-in-1-1" title="Permalink to this headline"></a></h2>
<ul class="simple">
<li>Fixed a cosmetic bug in the Django 1.4 admin. Action checkboxes now only appear once.</li>
<li>Template tags are refactored to allow easy use of any model derived from <tt class="docutils literal"><span class="pre">CategoryBase</span></tt>.</li>
<li>Improved test suite.</li>
<li>Improved some of the documentation.</li>
</ul>
</div>
<div class="section" id="contents">
<h2>Contents<a class="headerlink" href="#contents" title="Permalink to this headline"></a></h2>
@ -147,7 +135,7 @@
<li class="toctree-l2"><a class="reference internal" href="reference/management_commands.html">Management Commands</a></li>
<li class="toctree-l2"><a class="reference internal" href="reference/models.html">Models</a></li>
<li class="toctree-l2"><a class="reference internal" href="reference/settings.html">Settings</a></li>
<li class="toctree-l2"><a class="reference internal" href="reference/templatetags.html">Template Tags</a></li>
<li class="toctree-l2"><a class="reference internal" href="reference/templatetags.html">Template tags and filters</a></li>
</ul>
</li>
</ul>
@ -170,13 +158,13 @@
<div class="footer">
<p>
&copy; Copyright 2010-2012, Corey Oordt.
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.2.
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.0.7.
</p>
</div>
<div class="clearer"></div>
</div>
<div id="breadcrumbs">
Django Categories v 1.0
Django Categories v 1.1
</ul>
</div>
<script type="text/javascript" charset="utf-8" src="_static/toc.js"></script>

View file

@ -2,20 +2,17 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Installation &mdash; Django Categories 1.0.5 documentation</title>
<title>Installation &mdash; Django Categories v1.1 documentation</title>
<link rel="stylesheet" href="_static/default.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: '',
VERSION: '1.0.5',
VERSION: '1.1',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true
@ -24,13 +21,13 @@
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/underscore.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<link rel="top" title="Django Categories 1.0.5 documentation" href="index.html" />
<link rel="top" title="Django Categories v1.1 documentation" href="index.html" />
<link rel="next" title="Getting Started" href="getting_started.html" />
<link rel="prev" title="Django Categories v 1.0" href="index.html" />
<link rel="prev" title="Django Categories v 1.1" href="index.html" />
</head>
<body>
<div id="docstitle">
<p>Django Categories 1.0.5 documentation</p>
<p>Django Categories v1.1 documentation</p>
</div>
<div id="header">
<div id="title"><h1>Installation</h1></div>
@ -39,7 +36,7 @@
<li id="page_buttons">
<div class="headerButton"><a href="genindex.html" title="General Index" accesskey="I">index</a></div>
<div class="headerButton"><a href="getting_started.html" title="Getting Started" accesskey="N">next</a></div>
<div class="headerButton"><a href="index.html" title="Django Categories v 1.0" accesskey="P">previous</a></div>
<div class="headerButton"><a href="index.html" title="Django Categories v 1.1" accesskey="P">previous</a></div>
</li>
</ul>
</div>
@ -144,7 +141,7 @@
<div class="footer">
<p>
&copy; Copyright 2010-2012, Corey Oordt.
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.2.
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.0.7.
</p>
</div>
<div class="clearer"></div>

Binary file not shown.

View file

@ -2,20 +2,17 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Reference &mdash; Django Categories 1.0.5 documentation</title>
<title>Reference &mdash; Django Categories v1.1 documentation</title>
<link rel="stylesheet" href="../_static/default.css" type="text/css" />
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: '../',
VERSION: '1.0.5',
VERSION: '1.1',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true
@ -24,13 +21,13 @@
<script type="text/javascript" src="../_static/jquery.js"></script>
<script type="text/javascript" src="../_static/underscore.js"></script>
<script type="text/javascript" src="../_static/doctools.js"></script>
<link rel="top" title="Django Categories 1.0.5 documentation" href="../index.html" />
<link rel="top" title="Django Categories v1.1 documentation" href="../index.html" />
<link rel="next" title="Management Commands" href="management_commands.html" />
<link rel="prev" title="Creating Custom Categories" href="../custom_categories.html" />
</head>
<body>
<div id="docstitle">
<p>Django Categories 1.0.5 documentation</p>
<p>Django Categories v1.1 documentation</p>
</div>
<div id="header">
<div id="title"><h1>Reference</h1></div>
@ -58,7 +55,7 @@
<li class="toctree-l2"><a class="reference internal" href="management_commands.html">Management Commands</a></li>
<li class="toctree-l2"><a class="reference internal" href="models.html">Models</a></li>
<li class="toctree-l2"><a class="reference internal" href="settings.html">Settings</a></li>
<li class="toctree-l2"><a class="reference internal" href="templatetags.html">Template Tags</a></li>
<li class="toctree-l2"><a class="reference internal" href="templatetags.html">Template tags and filters</a></li>
</ul>
</li>
</ul>
@ -123,12 +120,10 @@
<li class="toctree-l2"><a class="reference internal" href="settings.html#javascript-url">JAVASCRIPT_URL</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="templatetags.html">Template Tags</a><ul>
<li class="toctree-l2"><a class="reference internal" href="templatetags.html#get-top-level-categories">get_top_level_categories</a></li>
<li class="toctree-l2"><a class="reference internal" href="templatetags.html#display-path-as-ul">display_path_as_ul</a></li>
<li class="toctree-l2"><a class="reference internal" href="templatetags.html#get-category-drilldown">get_category_drilldown</a></li>
<li class="toctree-l2"><a class="reference internal" href="templatetags.html#display-drilldown-as-ul">display_drilldown_as_ul</a></li>
<li class="toctree-l2"><a class="reference internal" href="templatetags.html#breadcrumbs-tag">breadcrumbs tag</a></li>
<li class="toctree-l1"><a class="reference internal" href="templatetags.html">Template tags and filters</a><ul>
<li class="toctree-l2"><a class="reference internal" href="templatetags.html#filters">Filters</a></li>
<li class="toctree-l2"><a class="reference internal" href="templatetags.html#inclusion-tags">Inclusion tags</a></li>
<li class="toctree-l2"><a class="reference internal" href="templatetags.html#template-tags">Template Tags</a></li>
</ul>
</li>
</ul>
@ -142,7 +137,7 @@
<div class="footer">
<p>
&copy; Copyright 2010-2012, Corey Oordt.
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.2.
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.0.7.
</p>
</div>
<div class="clearer"></div>

View file

@ -2,20 +2,17 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Management Commands &mdash; Django Categories 1.0.5 documentation</title>
<title>Management Commands &mdash; Django Categories v1.1 documentation</title>
<link rel="stylesheet" href="../_static/default.css" type="text/css" />
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: '../',
VERSION: '1.0.5',
VERSION: '1.1',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true
@ -24,14 +21,14 @@
<script type="text/javascript" src="../_static/jquery.js"></script>
<script type="text/javascript" src="../_static/underscore.js"></script>
<script type="text/javascript" src="../_static/doctools.js"></script>
<link rel="top" title="Django Categories 1.0.5 documentation" href="../index.html" />
<link rel="top" title="Django Categories v1.1 documentation" href="../index.html" />
<link rel="up" title="Reference" href="index.html" />
<link rel="next" title="Models" href="models.html" />
<link rel="prev" title="Reference" href="index.html" />
</head>
<body>
<div id="docstitle">
<p>Django Categories 1.0.5 documentation</p>
<p>Django Categories v1.1 documentation</p>
</div>
<div id="header">
<div id="title"><h1>Management Commands</h1></div>
@ -59,7 +56,7 @@
<li class="toctree-l2 current"><a class="current reference internal" href="">Management Commands</a></li>
<li class="toctree-l2"><a class="reference internal" href="models.html">Models</a></li>
<li class="toctree-l2"><a class="reference internal" href="settings.html">Settings</a></li>
<li class="toctree-l2"><a class="reference internal" href="templatetags.html">Template Tags</a></li>
<li class="toctree-l2"><a class="reference internal" href="templatetags.html">Template tags and filters</a></li>
</ul>
</li>
</ul>
@ -124,7 +121,7 @@
<div class="footer">
<p>
&copy; Copyright 2010-2012, Corey Oordt.
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.2.
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.0.7.
</p>
</div>
<div class="clearer"></div>

View file

@ -2,20 +2,17 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Models &mdash; Django Categories 1.0.5 documentation</title>
<title>Models &mdash; Django Categories v1.1 documentation</title>
<link rel="stylesheet" href="../_static/default.css" type="text/css" />
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: '../',
VERSION: '1.0.5',
VERSION: '1.1',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true
@ -24,14 +21,14 @@
<script type="text/javascript" src="../_static/jquery.js"></script>
<script type="text/javascript" src="../_static/underscore.js"></script>
<script type="text/javascript" src="../_static/doctools.js"></script>
<link rel="top" title="Django Categories 1.0.5 documentation" href="../index.html" />
<link rel="top" title="Django Categories v1.1 documentation" href="../index.html" />
<link rel="up" title="Reference" href="index.html" />
<link rel="next" title="Settings" href="settings.html" />
<link rel="prev" title="Management Commands" href="management_commands.html" />
</head>
<body>
<div id="docstitle">
<p>Django Categories 1.0.5 documentation</p>
<p>Django Categories v1.1 documentation</p>
</div>
<div id="header">
<div id="title"><h1>Models</h1></div>
@ -59,7 +56,7 @@
<li class="toctree-l2"><a class="reference internal" href="management_commands.html">Management Commands</a></li>
<li class="toctree-l2 current"><a class="current reference internal" href="">Models</a></li>
<li class="toctree-l2"><a class="reference internal" href="settings.html">Settings</a></li>
<li class="toctree-l2"><a class="reference internal" href="templatetags.html">Template Tags</a></li>
<li class="toctree-l2"><a class="reference internal" href="templatetags.html">Template tags and filters</a></li>
</ul>
</li>
</ul>
@ -127,7 +124,7 @@
<dl class="attribute">
<dt id="CategoryBase.active">
<tt class="descname">active</tt><a class="headerlink" href="#CategoryBase.active" title="Permalink to this definition"></a></dt>
<dd><p><strong>Required</strong> <tt class="docutils literal"><span class="pre">BooleanField</span></tt> <em>default:</em> <tt class="docutils literal"><span class="pre">True</span></tt></p>
<dd><p><strong>Required</strong> <tt class="docutils literal"><span class="pre">BooleanField</span></tt> <em>default:</em> <tt class="xref docutils literal"><span class="pre">True</span></tt></p>
<p>Is this item active. If it is inactive, all children are set to inactive as well.</p>
</dd></dl>
@ -135,7 +132,7 @@
<dt id="CategoryBase.objects">
<tt class="descname">objects</tt><a class="headerlink" href="#CategoryBase.objects" title="Permalink to this definition"></a></dt>
<dd><p><tt class="docutils literal"><span class="pre">CategoryManager</span></tt></p>
<p>An object manager that adds an <tt class="docutils literal"><span class="pre">active</span></tt> method for only selecting items whose <tt class="docutils literal"><span class="pre">active</span></tt> attribute is <tt class="docutils literal"><span class="pre">True</span></tt>.</p>
<p>An object manager that adds an <tt class="docutils literal"><span class="pre">active</span></tt> method for only selecting items whose <tt class="docutils literal"><span class="pre">active</span></tt> attribute is <tt class="xref docutils literal"><span class="pre">True</span></tt>.</p>
</dd></dl>
<dl class="attribute">
@ -240,7 +237,7 @@
<div class="footer">
<p>
&copy; Copyright 2010-2012, Corey Oordt.
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.2.
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.0.7.
</p>
</div>
<div class="clearer"></div>

View file

@ -2,20 +2,17 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Settings &mdash; Django Categories 1.0.5 documentation</title>
<title>Settings &mdash; Django Categories v1.1 documentation</title>
<link rel="stylesheet" href="../_static/default.css" type="text/css" />
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: '../',
VERSION: '1.0.5',
VERSION: '1.1',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true
@ -24,14 +21,14 @@
<script type="text/javascript" src="../_static/jquery.js"></script>
<script type="text/javascript" src="../_static/underscore.js"></script>
<script type="text/javascript" src="../_static/doctools.js"></script>
<link rel="top" title="Django Categories 1.0.5 documentation" href="../index.html" />
<link rel="top" title="Django Categories v1.1 documentation" href="../index.html" />
<link rel="up" title="Reference" href="index.html" />
<link rel="next" title="Template Tags" href="templatetags.html" />
<link rel="next" title="Template tags and filters" href="templatetags.html" />
<link rel="prev" title="Models" href="models.html" />
</head>
<body>
<div id="docstitle">
<p>Django Categories 1.0.5 documentation</p>
<p>Django Categories v1.1 documentation</p>
</div>
<div id="header">
<div id="title"><h1>Settings</h1></div>
@ -39,7 +36,7 @@
<li id="toc_button"><div class="headerButton"><a href="#">Table of Contents</a></div></li>
<li id="page_buttons">
<div class="headerButton"><a href="../genindex.html" title="General Index" accesskey="I">index</a></div>
<div class="headerButton"><a href="templatetags.html" title="Template Tags" accesskey="N">next</a></div>
<div class="headerButton"><a href="templatetags.html" title="Template tags and filters" accesskey="N">next</a></div>
<div class="headerButton"><a href="models.html" title="Models" accesskey="P">previous</a></div>
</li>
</ul>
@ -59,7 +56,7 @@
<li class="toctree-l2"><a class="reference internal" href="management_commands.html">Management Commands</a></li>
<li class="toctree-l2"><a class="reference internal" href="models.html">Models</a></li>
<li class="toctree-l2 current"><a class="current reference internal" href="">Settings</a></li>
<li class="toctree-l2"><a class="reference internal" href="templatetags.html">Template Tags</a></li>
<li class="toctree-l2"><a class="reference internal" href="templatetags.html">Template tags and filters</a></li>
</ul>
</li>
</ul>
@ -128,8 +125,8 @@
</div>
<div class="section" id="allow-slug-change">
<span id="id1"></span><h2><a class="toc-backref" href="#id11">ALLOW_SLUG_CHANGE</a><a class="headerlink" href="#allow-slug-change" title="Permalink to this headline"></a></h2>
<p><strong>Default:</strong> <tt class="docutils literal"><span class="pre">False</span></tt></p>
<p><strong>Description:</strong> Changing the slug for a category can have serious consequences if it is used as part of a URL. Setting this to <tt class="docutils literal"><span class="pre">True</span></tt> will allow users to change the slug of a category.</p>
<p><strong>Default:</strong> <tt class="xref docutils literal"><span class="pre">False</span></tt></p>
<p><strong>Description:</strong> Changing the slug for a category can have serious consequences if it is used as part of a URL. Setting this to <tt class="xref docutils literal"><span class="pre">True</span></tt> will allow users to change the slug of a category.</p>
</div>
<div class="section" id="slug-transliterator">
<span id="id2"></span><h2><a class="toc-backref" href="#id12">SLUG_TRANSLITERATOR</a><a class="headerlink" href="#slug-transliterator" title="Permalink to this headline"></a></h2>
@ -159,7 +156,7 @@
</div>
<div class="section" id="register-admin">
<span id="thumbnail-upload-path"></span><span id="id7"></span><h2><a class="toc-backref" href="#id17">REGISTER_ADMIN</a><a class="headerlink" href="#register-admin" title="Permalink to this headline"></a></h2>
<p><strong>Default:</strong> <tt class="docutils literal"><span class="pre">True</span></tt></p>
<p><strong>Default:</strong> <tt class="xref docutils literal"><span class="pre">True</span></tt></p>
<p><strong>Description:</strong> If you write your own category class by subclassing <tt class="docutils literal"><span class="pre">CategoryBase</span></tt> then you probably have no use for registering the default <tt class="docutils literal"><span class="pre">Category</span></tt> class in the admin.</p>
</div>
<div class="section" id="id8">
@ -186,7 +183,7 @@
<div class="footer">
<p>
&copy; Copyright 2010-2012, Corey Oordt.
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.2.
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.0.7.
</p>
</div>
<div class="clearer"></div>

View file

@ -2,20 +2,17 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Template Tags &mdash; Django Categories 1.0.5 documentation</title>
<title>Template tags and filters &mdash; Django Categories v1.1 documentation</title>
<link rel="stylesheet" href="../_static/default.css" type="text/css" />
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: '../',
VERSION: '1.0.5',
VERSION: '1.1',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true
@ -24,16 +21,16 @@
<script type="text/javascript" src="../_static/jquery.js"></script>
<script type="text/javascript" src="../_static/underscore.js"></script>
<script type="text/javascript" src="../_static/doctools.js"></script>
<link rel="top" title="Django Categories 1.0.5 documentation" href="../index.html" />
<link rel="top" title="Django Categories v1.1 documentation" href="../index.html" />
<link rel="up" title="Reference" href="index.html" />
<link rel="prev" title="Settings" href="settings.html" />
</head>
<body>
<div id="docstitle">
<p>Django Categories 1.0.5 documentation</p>
<p>Django Categories v1.1 documentation</p>
</div>
<div id="header">
<div id="title"><h1>Template Tags</h1></div>
<div id="title"><h1>Template tags and filters</h1></div>
<ul id="headerButtons">
<li id="toc_button"><div class="headerButton"><a href="#">Table of Contents</a></div></li>
<li id="page_buttons">
@ -57,7 +54,7 @@
<li class="toctree-l2"><a class="reference internal" href="management_commands.html">Management Commands</a></li>
<li class="toctree-l2"><a class="reference internal" href="models.html">Models</a></li>
<li class="toctree-l2"><a class="reference internal" href="settings.html">Settings</a></li>
<li class="toctree-l2 current"><a class="current reference internal" href="">Template Tags</a></li>
<li class="toctree-l2 current"><a class="current reference internal" href="">Template tags and filters</a></li>
</ul>
</li>
</ul>
@ -94,25 +91,128 @@
<div class="bodywrapper">
<div class="body">
<div class="section" id="template-tags">
<h1>Template Tags<a class="headerlink" href="#template-tags" title="Permalink to this headline"></a></h1>
<div class="section" id="get-top-level-categories">
<h2>get_top_level_categories<a class="headerlink" href="#get-top-level-categories" title="Permalink to this headline"></a></h2>
<p>Retrieves an alphabetical list of all the categories that have no parents.</p>
<p>Syntax:</p>
<div class="highlight-django"><div class="highlight"><pre><span class="cp">{%</span> <span class="k">get_top_level_categories</span> <span class="k">as</span> <span class="nv">categories</span> <span class="cp">%}</span><span class="x"></span>
<div class="section" id="template-tags-and-filters">
<h1>Template tags and filters<a class="headerlink" href="#template-tags-and-filters" title="Permalink to this headline"></a></h1>
<div class="contents local topic" id="contents">
<ul class="simple">
<li><a class="reference internal" href="#filters" id="id2">Filters</a><ul>
<li><a class="reference internal" href="#category-path" id="id3"><tt class="docutils literal"><span class="pre">category_path</span></tt></a></li>
<li><a class="reference internal" href="#tree-info" id="id4"><tt class="docutils literal"><span class="pre">tree_info</span></tt></a></li>
<li><a class="reference internal" href="#tree-queryset" id="id5"><tt class="docutils literal"><span class="pre">tree_queryset</span></tt></a></li>
</ul>
</li>
<li><a class="reference internal" href="#inclusion-tags" id="id6">Inclusion tags</a><ul>
<li><a class="reference internal" href="#display-path-as-ul" id="id7"><tt class="docutils literal"><span class="pre">display_path_as_ul</span></tt></a></li>
<li><a class="reference internal" href="#display-drilldown-as-ul" id="id8"><tt class="docutils literal"><span class="pre">display_drilldown_as_ul</span></tt></a></li>
<li><a class="reference internal" href="#breadcrumbs-tag" id="id9"><tt class="docutils literal"><span class="pre">breadcrumbs</span> <span class="pre">tag</span></tt></a></li>
</ul>
</li>
<li><a class="reference internal" href="#template-tags" id="id10">Template Tags</a><ul>
<li><a class="reference internal" href="#get-top-level-categories" id="id11"><tt class="docutils literal"><span class="pre">get_top_level_categories</span></tt></a></li>
<li><a class="reference internal" href="#get-category-drilldown" id="id12"><tt class="docutils literal"><span class="pre">get_category_drilldown</span></tt></a></li>
<li><a class="reference internal" href="#recursetree" id="id13"><tt class="docutils literal"><span class="pre">recursetree</span></tt></a></li>
</ul>
</li>
</ul>
</div>
<div class="section" id="filters">
<h2><a class="toc-backref" href="#contents">Filters</a><a class="headerlink" href="#filters" title="Permalink to this headline"></a></h2>
<div class="section" id="category-path">
<h3><a class="toc-backref" href="#contents"><tt class="docutils literal"><span class="pre">category_path</span></tt></a><a class="headerlink" href="#category-path" title="Permalink to this headline"></a></h3>
<p><strong>Optional Parameter:</strong> separator string. <em>Default:</em> <tt class="docutils literal"><span class="pre">&quot;</span> <span class="pre">::</span> <span class="pre">&quot;</span></tt></p>
<p>Creates a path represented by a categories by joining the items with a separator.</p>
<p>Each path item will be coerced to unicode, so you can pass a list of category instances, if required.</p>
<p><strong>Example using a list of categories:</strong></p>
<div class="highlight-django"><div class="highlight"><pre><span class="cp">{{</span> <span class="nv">some_list</span><span class="o">|</span><span class="nf">category_path</span> <span class="cp">}}</span><span class="x"></span>
</pre></div>
</div>
<p>Returns an list of categories <tt class="docutils literal"><span class="pre">[&lt;category&gt;,</span> <span class="pre">&lt;category&gt;,</span> <span class="pre">&lt;category,</span> <span class="pre">...]</span></tt></p>
<p>If <tt class="docutils literal"><span class="pre">some_list</span></tt> is <tt class="docutils literal"><span class="pre">[</span> <span class="pre">&lt;Category:</span> <span class="pre">Country&gt;,</span> <span class="pre">&lt;Category:</span> <span class="pre">Country</span> <span class="pre">pop&gt;,</span> <span class="pre">&lt;Category:</span> <span class="pre">Urban</span> <span class="pre">Cowboy&gt;]</span></tt> the result will be:</p>
<div class="highlight-python"><pre>Country :: Country pop :: Urban Cowboy</pre>
</div>
<p><strong>Example using a category node and optional separator parameter:</strong></p>
<div class="highlight-django"><div class="highlight"><pre><span class="cp">{{</span> <span class="nv">some_node.get_ancestors</span><span class="o">|</span><span class="nf">category_path</span><span class="s2">:&quot; &gt; &quot;</span> <span class="cp">}}</span><span class="x"></span>
</pre></div>
</div>
<p>If <tt class="docutils literal"><span class="pre">some_node</span></tt> was category &#8220;Urban Cowboy&#8221;, the result will be:</p>
<div class="highlight-python"><pre>Country &gt; Country pop &gt; Urban Cowboy</pre>
</div>
</div>
<div class="section" id="tree-info">
<span id="id1"></span><h3><a class="toc-backref" href="#contents"><tt class="docutils literal"><span class="pre">tree_info</span></tt></a><a class="headerlink" href="#tree-info" title="Permalink to this headline"></a></h3>
<p><strong>Optional Parameter:</strong> <tt class="docutils literal"><span class="pre">&quot;ancestors&quot;</span></tt></p>
<p>Given a list of categories, it iterates over the list, generating a tuple of the current category and a dict containing information about the tree structure around it, with the following keys:</p>
<dl class="docutils">
<dt><tt class="docutils literal"><span class="pre">'new_level'</span></tt></dt>
<dd><tt class="xref docutils literal"><span class="pre">True</span></tt> if the current item is the start of a new level in the tree, <tt class="xref docutils literal"><span class="pre">False</span></tt> otherwise.</dd>
<dt><tt class="docutils literal"><span class="pre">'closed_levels'</span></tt></dt>
<dd>A list of levels which end after the current item. This will be an empty list if the next category&#8217;s level is the same as or greater than the level of the current item.</dd>
</dl>
<p>Provide the optional argument, <tt class="docutils literal"><span class="pre">&quot;ancestors&quot;</span></tt>, to add a list of unicode representations of the ancestors of the current category, in descending order (root node first, immediate parent last), under the key &#8216;ancestors&#8217;.</p>
<p>For example: given the sample tree below, the contents of the list which would be available under the &#8216;ancestors&#8217; key are given on the right:</p>
<div class="highlight-python"><pre>Country -&gt; []
Country pop -&gt; [u'Country pop']
Urban Cowboy -&gt; [u'Country', u'Country pop']</pre>
</div>
<p>Using this filter with unpacking in a {% for %} tag, you should have enough information about the tree structure to create a hierarchical representation of the tree.</p>
<div class="highlight-django"><div class="highlight"><pre><span class="cp">{%</span> <span class="k">for</span> <span class="nv">node</span><span class="o">,</span><span class="nv">structure</span> <span class="k">in</span> <span class="nv">objects</span><span class="o">|</span><span class="nf">tree_info</span> <span class="cp">%}</span><span class="x"></span>
<span class="x"> </span><span class="cp">{%</span> <span class="k">if</span> <span class="nv">structure.new_level</span> <span class="cp">%}</span><span class="x">&lt;ul&gt;&lt;li&gt;</span><span class="cp">{%</span> <span class="k">else</span> <span class="cp">%}</span><span class="x">&lt;/li&gt;&lt;li&gt;</span><span class="cp">{%</span> <span class="k">endif</span> <span class="cp">%}</span><span class="x"></span>
<span class="x"> </span><span class="cp">{{</span> <span class="nv">node.name</span> <span class="cp">}}</span><span class="x"></span>
<span class="x"> </span><span class="cp">{%</span> <span class="k">for</span> <span class="nv">level</span> <span class="k">in</span> <span class="nv">structure.closed_levels</span> <span class="cp">%}</span><span class="x">&lt;/li&gt;&lt;/ul&gt;</span><span class="cp">{%</span> <span class="k">endfor</span> <span class="cp">%}</span><span class="x"></span>
<span class="cp">{%</span> <span class="k">endfor</span> <span class="cp">%}</span><span class="x"></span>
</pre></div>
</div>
</div>
<div class="section" id="tree-queryset">
<h3><a class="toc-backref" href="#contents"><tt class="docutils literal"><span class="pre">tree_queryset</span></tt></a><a class="headerlink" href="#tree-queryset" title="Permalink to this headline"></a></h3>
<p>Convert a regular category <tt class="xref py py-class docutils literal"><span class="pre">QuerySet</span></tt> into a new, ordered <tt class="xref py py-class docutils literal"><span class="pre">QuerySet</span></tt> that includes the categories selected and their ancestors.</p>
<p>This is especially helpful when you have a subset of categories and want to show the hierarchy for all the items.</p>
<p>For example, if we add it to the example for <a class="reference internal" href="#tree-info"><em>tree_info</em></a>:</p>
<div class="highlight-django"><div class="highlight"><pre><span class="cp">{%</span> <span class="k">for</span> <span class="nv">node</span><span class="o">,</span><span class="nv">structure</span> <span class="k">in</span> <span class="nv">objects</span><span class="o">|</span><span class="nf">tree_queryset</span><span class="o">|</span><span class="nf">tree_info</span> <span class="cp">%}</span><span class="x"></span>
<span class="x"> </span><span class="cp">{%</span> <span class="k">if</span> <span class="nv">structure.new_level</span> <span class="cp">%}</span><span class="x">&lt;ul&gt;&lt;li&gt;</span><span class="cp">{%</span> <span class="k">else</span> <span class="cp">%}</span><span class="x">&lt;/li&gt;&lt;li&gt;</span><span class="cp">{%</span> <span class="k">endif</span> <span class="cp">%}</span><span class="x"></span>
<span class="x"> </span><span class="cp">{{</span> <span class="nv">node.name</span> <span class="cp">}}</span><span class="x"></span>
<span class="x"> </span><span class="cp">{%</span> <span class="k">for</span> <span class="nv">level</span> <span class="k">in</span> <span class="nv">structure.closed_levels</span> <span class="cp">%}</span><span class="x">&lt;/li&gt;&lt;/ul&gt;</span><span class="cp">{%</span> <span class="k">endfor</span> <span class="cp">%}</span><span class="x"></span>
<span class="cp">{%</span> <span class="k">endfor</span> <span class="cp">%}</span><span class="x"></span>
</pre></div>
</div>
<p>A list of unrelated categories such as <tt class="docutils literal"><span class="pre">[&lt;Category:</span> <span class="pre">Urban</span> <span class="pre">cowboy&gt;,</span> <span class="pre">&lt;Category:</span> <span class="pre">Urban</span> <span class="pre">comtemporary&gt;]</span></tt>, the above template example will output the two categories and their ancestors:</p>
<div class="highlight-html"><div class="highlight"><pre><span class="nt">&lt;ul&gt;&lt;li&gt;</span>
Country
<span class="nt">&lt;ul&gt;&lt;li&gt;</span>
Country pop
<span class="nt">&lt;ul&gt;&lt;li&gt;</span>
Urban cowboy
<span class="nt">&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;</span>
<span class="nt">&lt;ul&gt;&lt;li&gt;</span>
Rhythm and blues
<span class="nt">&lt;ul&gt;&lt;li&gt;</span>
Urban contemporary
<span class="nt">&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;</span>
</pre></div>
</div>
<div class="admonition note">
<p class="first admonition-title">Note</p>
<p class="last">Categories that have similar ancestors are grouped accordingly. There is no duplication of the ancestor tree.</p>
</div>
</div>
</div>
<div class="section" id="inclusion-tags">
<h2><a class="toc-backref" href="#contents">Inclusion tags</a><a class="headerlink" href="#inclusion-tags" title="Permalink to this headline"></a></h2>
<div class="section" id="display-path-as-ul">
<h2>display_path_as_ul<a class="headerlink" href="#display-path-as-ul" title="Permalink to this headline"></a></h2>
<p>Render the category with ancestors, but no children using the <tt class="docutils literal"><span class="pre">categories/ul_tree.html</span></tt> template.</p>
<p>Example:</p>
<h3><a class="toc-backref" href="#contents"><tt class="docutils literal"><span class="pre">display_path_as_ul</span></tt></a><a class="headerlink" href="#display-path-as-ul" title="Permalink to this headline"></a></h3>
<p><strong>Template Rendered:</strong> <tt class="docutils literal"><span class="pre">categories/ul_tree.html</span></tt></p>
<p><strong>Syntax 1:</strong> <tt class="docutils literal"><span class="pre">{%</span> <span class="pre">display_path_as_ul</span> <span class="pre">&lt;category_obj&gt;</span> <span class="pre">%}</span></tt></p>
<p><strong>Syntax 2:</strong> <tt class="docutils literal"><span class="pre">{%</span> <span class="pre">display_path_as_ul</span> <span class="pre">&lt;path_string&gt;[</span> <span class="pre">using=&quot;app.Model&quot;]</span> <span class="pre">%}</span></tt></p>
<p>Render the category with ancestors, but no children.</p>
<p>Pass either an object that subclasses <a class="reference internal" href="models.html#CategoryBase" title="CategoryBase"><tt class="xref py py-class docutils literal"><span class="pre">CategoryBase</span></tt></a> or a path string for the category. Add <tt class="docutils literal"><span class="pre">using=&quot;app.Model&quot;</span></tt> to specify which model when using a path string. The default model used is <a class="reference internal" href="models.html#Category" title="Category"><tt class="xref py py-class docutils literal"><span class="pre">Category</span></tt></a>.</p>
<p><strong>Example, using Category model:</strong></p>
<div class="highlight-django"><div class="highlight"><pre><span class="cp">{%</span> <span class="k">display_path_as_ul</span> <span class="s2">&quot;/Grandparent/Parent&quot;</span> <span class="cp">%}</span><span class="x"></span>
</pre></div>
</div>
<p>or</p>
<p><strong>Example, using custom model:</strong></p>
<div class="highlight-django"><div class="highlight"><pre><span class="cp">{%</span> <span class="k">display_path_as_ul</span> <span class="s2">&quot;/Grandparent/Parent&quot;</span> <span class="nv">using</span><span class="o">=</span><span class="s2">&quot;coolapp.MusicGenre&quot;</span> <span class="cp">%}</span><span class="x"></span>
</pre></div>
</div>
<p><strong>Example, using an object:</strong></p>
<div class="highlight-django"><div class="highlight"><pre><span class="cp">{%</span> <span class="k">display_path_as_ul</span> <span class="nv">category_obj</span> <span class="cp">%}</span><span class="x"></span>
</pre></div>
</div>
@ -127,31 +227,21 @@
</pre></div>
</div>
</div>
<div class="section" id="get-category-drilldown">
<h2>get_category_drilldown<a class="headerlink" href="#get-category-drilldown" title="Permalink to this headline"></a></h2>
<p>Retrieves the specified category, its ancestors and its immediate children
as an iterable.</p>
<p>Example:</p>
<div class="highlight-django"><div class="highlight"><pre><span class="cp">{%</span> <span class="k">get_category_drilldown</span> <span class="s2">&quot;/Grandparent/Parent&quot;</span> <span class="k">as</span> <span class="nv">family</span> <span class="cp">%}</span><span class="x"></span>
</pre></div>
</div>
<p>or</p>
<div class="highlight-django"><div class="highlight"><pre><span class="cp">{%</span> <span class="k">get_category_drilldown</span> <span class="nv">category_obj</span> <span class="k">as</span> <span class="nv">family</span> <span class="cp">%}</span><span class="x"></span>
</pre></div>
</div>
<p>Sets <tt class="docutils literal"><span class="pre">family</span></tt> to:</p>
<div class="highlight-python"><pre>[Grandparent, Parent, Child 1, Child 2, Child n]</pre>
</div>
</div>
<div class="section" id="display-drilldown-as-ul">
<h2>display_drilldown_as_ul<a class="headerlink" href="#display-drilldown-as-ul" title="Permalink to this headline"></a></h2>
<p>Render the category with ancestors and children using the
<tt class="docutils literal"><span class="pre">categories/ul_tree.html</span></tt> template.</p>
<p>Example:</p>
<h3><a class="toc-backref" href="#contents"><tt class="docutils literal"><span class="pre">display_drilldown_as_ul</span></tt></a><a class="headerlink" href="#display-drilldown-as-ul" title="Permalink to this headline"></a></h3>
<p><strong>Template rendered:</strong> <tt class="docutils literal"><span class="pre">categories/ul_tree.html</span></tt></p>
<p><strong>Syntax 1:</strong> <tt class="docutils literal"><span class="pre">{%</span> <span class="pre">display_drilldown_as_ul</span> <span class="pre">category_obj</span> <span class="pre">%}</span></tt></p>
<p><strong>Syntax 2:</strong> <tt class="docutils literal"><span class="pre">{%</span> <span class="pre">display_drilldown_as_ul</span> <span class="pre">&quot;/Grandparent/Parent&quot;</span> <span class="pre">[using=&quot;app.Model&quot;]</span> <span class="pre">%}</span></tt></p>
<p>Render the category with ancestors and children.</p>
<p><strong>Example, using Category model:</strong></p>
<div class="highlight-django"><div class="highlight"><pre><span class="cp">{%</span> <span class="k">display_drilldown_as_ul</span> <span class="s2">&quot;/Grandparent/Parent&quot;</span> <span class="cp">%}</span><span class="x"></span>
</pre></div>
</div>
<p>or:</p>
<p><strong>Example, using custom model:</strong></p>
<div class="highlight-django"><div class="highlight"><pre><span class="cp">{%</span> <span class="k">display_drilldown_as_ul</span> <span class="s2">&quot;/Grandparent/Parent&quot;</span> <span class="nv">using</span><span class="o">=</span><span class="s2">&quot;coolapp.MusicGenre&quot;</span> <span class="cp">%}</span><span class="x"></span>
</pre></div>
</div>
<p><strong>Example, using an object:</strong></p>
<div class="highlight-django"><div class="highlight"><pre><span class="cp">{%</span> <span class="k">display_drilldown_as_ul</span> <span class="nv">category_obj</span> <span class="cp">%}</span><span class="x"></span>
</pre></div>
</div>
@ -177,13 +267,20 @@ as an iterable.</p>
</div>
</div>
<div class="section" id="breadcrumbs-tag">
<h2>breadcrumbs tag<a class="headerlink" href="#breadcrumbs-tag" title="Permalink to this headline"></a></h2>
<p>Render breadcrumbs, using the <tt class="docutils literal"><span class="pre">categories/breadcrumbs.html</span></tt> template, using the optional <tt class="docutils literal"><span class="pre">separator</span></tt> argument.</p>
<p>Example:</p>
<h3><a class="toc-backref" href="#contents"><tt class="docutils literal"><span class="pre">breadcrumbs</span> <span class="pre">tag</span></tt></a><a class="headerlink" href="#breadcrumbs-tag" title="Permalink to this headline"></a></h3>
<p><strong>Template rendered:</strong> <tt class="docutils literal"><span class="pre">categories/breadcrumbs.html</span></tt></p>
<p><strong>Syntax 1:</strong> <tt class="docutils literal"><span class="pre">{%</span> <span class="pre">breadcrumbs</span> <span class="pre">category_obj</span> <span class="pre">[separator=&quot;</span> <span class="pre">::</span> <span class="pre">&quot;]</span> <span class="pre">%}</span></tt></p>
<p><strong>Syntax 2:</strong> <tt class="docutils literal"><span class="pre">{%</span> <span class="pre">breadcrumbs</span> <span class="pre">&quot;/Grandparent/Parent&quot;</span> <span class="pre">[separator=&quot;</span> <span class="pre">::</span> <span class="pre">&quot;]</span> <span class="pre">[using=&quot;app.Model&quot;]</span> <span class="pre">%}</span></tt></p>
<p>Render breadcrumbs for the given path using <tt class="docutils literal"><span class="pre">::</span></tt> or the given separator.</p>
<p><strong>Example using Category model:</strong></p>
<div class="highlight-django"><div class="highlight"><pre><span class="cp">{%</span> <span class="k">breadcrumbs</span> <span class="s2">&quot;/Grandparent/Parent&quot;</span> <span class="cp">%}</span><span class="x"></span>
</pre></div>
</div>
<p>or:</p>
<p><strong>Example using a custom model:</strong></p>
<div class="highlight-django"><div class="highlight"><pre><span class="cp">{%</span> <span class="k">breadcrumbs</span> <span class="s2">&quot;/Grandparent/Parent&quot;</span> <span class="nv">using</span><span class="o">=</span><span class="s2">&quot;coolapp.MusicGenre&quot;</span> <span class="cp">%}</span><span class="x"></span>
</pre></div>
</div>
<p><strong>Example using an object:</strong></p>
<div class="highlight-django"><div class="highlight"><pre><span class="cp">{%</span> <span class="k">breadcrumbs</span> <span class="nv">category_obj</span> <span class="cp">%}</span><span class="x"></span>
</pre></div>
</div>
@ -191,15 +288,87 @@ as an iterable.</p>
<div class="highlight-html"><div class="highlight"><pre><span class="nt">&lt;a</span> <span class="na">href=</span><span class="s">&quot;/categories/grandparent/&quot;</span><span class="nt">&gt;</span>Grandparent<span class="nt">&lt;/a&gt;</span> / Parent
</pre></div>
</div>
<p>You can alter the separator used in the template by adding a string argument to be the separator:</p>
<div class="highlight-django"><div class="highlight"><pre><span class="cp">{%</span> <span class="k">breadcrumbs</span> <span class="nv">category_obj</span> <span class="s2">&quot;::&quot;</span> <span class="cp">%}</span><span class="x"></span>
<p>You can alter the separator used in the template by adding a separator argument:</p>
<div class="highlight-django"><div class="highlight"><pre><span class="cp">{%</span> <span class="k">breadcrumbs</span> <span class="nv">category_obj</span> <span class="nv">separator</span><span class="o">=</span><span class="s2">&quot; &amp;gt; &quot;</span> <span class="cp">%}</span><span class="x"></span>
</pre></div>
</div>
<p>Returns:</p>
<div class="highlight-html"><div class="highlight"><pre><span class="nt">&lt;a</span> <span class="na">href=</span><span class="s">&quot;/categories/grandparent/&quot;</span><span class="nt">&gt;</span>Grandparent<span class="nt">&lt;/a&gt;</span> :: Parent
<div class="highlight-html"><div class="highlight"><pre><span class="nt">&lt;a</span> <span class="na">href=</span><span class="s">&quot;/categories/grandparent/&quot;</span><span class="nt">&gt;</span>Grandparent<span class="nt">&lt;/a&gt;</span> <span class="ni">&amp;gt;</span> Parent
</pre></div>
</div>
</div>
</div>
<div class="section" id="template-tags">
<h2><a class="toc-backref" href="#contents">Template Tags</a><a class="headerlink" href="#template-tags" title="Permalink to this headline"></a></h2>
<div class="section" id="get-top-level-categories">
<h3><a class="toc-backref" href="#contents"><tt class="docutils literal"><span class="pre">get_top_level_categories</span></tt></a><a class="headerlink" href="#get-top-level-categories" title="Permalink to this headline"></a></h3>
<p>Retrieves an alphabetical list of all the categories that have no parents.</p>
<p>Syntax:</p>
<div class="highlight-django"><div class="highlight"><pre><span class="cp">{%</span> <span class="k">get_top_level_categories</span> <span class="o">[</span><span class="nv">using</span> <span class="s2">&quot;app.Model&quot;</span><span class="o">]</span> <span class="k">as</span> <span class="nv">categories</span> <span class="cp">%}</span><span class="x"></span>
</pre></div>
</div>
<p>Returns an list of categories <tt class="docutils literal"><span class="pre">[&lt;category&gt;,</span> <span class="pre">&lt;category&gt;,</span> <span class="pre">&lt;category,</span> <span class="pre">...]</span></tt></p>
</div>
<div class="section" id="get-category-drilldown">
<h3><a class="toc-backref" href="#contents"><tt class="docutils literal"><span class="pre">get_category_drilldown</span></tt></a><a class="headerlink" href="#get-category-drilldown" title="Permalink to this headline"></a></h3>
<p><strong>Syntax 1:</strong> <tt class="docutils literal"><span class="pre">{%</span> <span class="pre">get_category_drilldown</span> <span class="pre">&lt;path_string&gt;</span> <span class="pre">[using</span> <span class="pre">&quot;app.Model&quot;]</span> <span class="pre">as</span> <span class="pre">&lt;varname&gt;</span> <span class="pre">%}</span></tt></p>
<p><strong>Syntax 2:</strong> <tt class="docutils literal"><span class="pre">{%</span> <span class="pre">get_category_drilldown</span> <span class="pre">&lt;object&gt;</span> <span class="pre">as</span> <span class="pre">&lt;varname&gt;</span> <span class="pre">%}</span></tt></p>
<p>Retrieves the specified category, its ancestors and its immediate children as an iterable. Syntax 1 allows for the retrieval of the category object via a slash-delimited path. The optional <tt class="docutils literal"><span class="pre">using</span> <span class="pre">&quot;app.Model&quot;</span></tt> allows you to specify from which model to retrieve the object.</p>
<p>Example:</p>
<div class="highlight-django"><div class="highlight"><pre><span class="cp">{%</span> <span class="k">get_category_drilldown</span> <span class="s2">&quot;/Grandparent/Parent&quot;</span> <span class="nv">using</span> <span class="s2">&quot;family.Member&quot;</span> <span class="k">as</span> <span class="nv">family</span> <span class="cp">%}</span><span class="x"></span>
</pre></div>
</div>
<p>The second syntax uses an instance of any object that subclasses <a class="reference internal" href="models.html#CategoryBase" title="CategoryBase"><tt class="xref py py-class docutils literal"><span class="pre">CategoryBase</span></tt></a></p>
<div class="highlight-django"><div class="highlight"><pre><span class="cp">{%</span> <span class="k">get_category_drilldown</span> <span class="nv">category_obj</span> <span class="k">as</span> <span class="nv">family</span> <span class="cp">%}</span><span class="x"></span>
</pre></div>
</div>
<p>Both examples sets <tt class="docutils literal"><span class="pre">family</span></tt> to:</p>
<div class="highlight-python"><pre>[Grandparent, Parent, Child 1, Child 2, Child n]</pre>
</div>
</div>
<div class="section" id="recursetree">
<h3><a class="toc-backref" href="#contents"><tt class="docutils literal"><span class="pre">recursetree</span></tt></a><a class="headerlink" href="#recursetree" title="Permalink to this headline"></a></h3>
<p>This tag renders a section of your template recursively for each node in your
tree.</p>
<p>For example:</p>
<div class="highlight-django"><div class="highlight"><pre><span class="x">&lt;ul class=&quot;root&quot;&gt;</span>
<span class="x"> </span><span class="cp">{%</span> <span class="k">recursetree</span> <span class="nv">nodes</span> <span class="cp">%}</span><span class="x"></span>
<span class="x"> &lt;li&gt;</span>
<span class="x"> </span><span class="cp">{{</span> <span class="nv">node.name</span> <span class="cp">}}</span><span class="x"></span>
<span class="x"> </span><span class="cp">{%</span> <span class="k">if</span> <span class="k">not</span> <span class="nv">node.is_leaf_node</span> <span class="cp">%}</span><span class="x"></span>
<span class="x"> &lt;ul class=&quot;children&quot;&gt;</span>
<span class="x"> </span><span class="cp">{{</span> <span class="nv">children</span> <span class="cp">}}</span><span class="x"></span>
<span class="x"> &lt;/ul&gt;</span>
<span class="x"> </span><span class="cp">{%</span> <span class="k">endif</span> <span class="cp">%}</span><span class="x"></span>
<span class="x"> &lt;/li&gt;</span>
<span class="x"> </span><span class="cp">{%</span> <span class="k">endrecursetree</span> <span class="cp">%}</span><span class="x"></span>
<span class="x">&lt;/ul&gt;</span>
</pre></div>
</div>
<p>Note the special variables <tt class="docutils literal"><span class="pre">node</span></tt> and <tt class="docutils literal"><span class="pre">children</span></tt>.
These are magically inserted into your context while you&#8217;re inside the
<tt class="docutils literal"><span class="pre">recursetree</span></tt> tag.</p>
<blockquote>
<div><p><tt class="docutils literal"><span class="pre">node</span></tt> is an instance of your MPTT model.</p>
<p><tt class="docutils literal"><span class="pre">children</span></tt> : This variable holds the rendered HTML for the children of
<tt class="docutils literal"><span class="pre">node</span></tt>.</p>
</div></blockquote>
<div class="admonition note">
<p class="first admonition-title">Note</p>
<p>If you already have variables called <tt class="docutils literal"><span class="pre">node</span></tt> or <tt class="docutils literal"><span class="pre">children</span></tt> in your
template, and you need to access them inside the <tt class="docutils literal"><span class="pre">recursetree</span></tt> block,
you&#8217;ll need to alias them to some other name first:</p>
<div class="last highlight-django"><div class="highlight"><pre><span class="cp">{%</span> <span class="k">with</span> <span class="nv">node</span> <span class="k">as</span> <span class="nv">friendly_node</span> <span class="cp">%}</span><span class="x"></span>
<span class="x"> </span><span class="cp">{%</span> <span class="k">recursetree</span> <span class="nv">nodes</span> <span class="cp">%}</span><span class="x"></span>
<span class="x"> </span><span class="cp">{{</span> <span class="nv">node.name</span> <span class="cp">}}</span><span class="x"> is friends with </span><span class="cp">{{</span> <span class="nv">friendly_node.name</span> <span class="cp">}}</span><span class="x"></span>
<span class="x"> </span><span class="cp">{{</span> <span class="nv">children</span> <span class="cp">}}</span><span class="x"></span>
<span class="x"> </span><span class="cp">{%</span> <span class="k">endrecursetree</span> <span class="cp">%}</span><span class="x"></span>
<span class="cp">{%</span> <span class="k">endwith</span> <span class="cp">%}</span><span class="x"></span>
</pre></div>
</div>
</div>
</div>
</div>
</div>
@ -209,14 +378,14 @@ as an iterable.</p>
<div class="footer">
<p>
&copy; Copyright 2010-2012, Corey Oordt.
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.2.
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.0.7.
</p>
</div>
<div class="clearer"></div>
</div>
<div id="breadcrumbs">
<a href="index.html" accesskey="U">Reference</a><img src="../_static/triangle_closed.png" height="9" width="9" alt="&gt;">
Template Tags
Template tags and filters
</ul>
</div>
<script type="text/javascript" charset="utf-8" src="../_static/toc.js"></script>

View file

@ -2,20 +2,17 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Registering Models &mdash; Django Categories 1.0.5 documentation</title>
<title>Registering Models &mdash; Django Categories v1.1 documentation</title>
<link rel="stylesheet" href="_static/default.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: '',
VERSION: '1.0.5',
VERSION: '1.1',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true
@ -24,13 +21,13 @@
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/underscore.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<link rel="top" title="Django Categories 1.0.5 documentation" href="index.html" />
<link rel="top" title="Django Categories v1.1 documentation" href="index.html" />
<link rel="next" title="Adding the fields to the database" href="adding_the_fields.html" />
<link rel="prev" title="Using categories in templates" href="usage.html" />
</head>
<body>
<div id="docstitle">
<p>Django Categories 1.0.5 documentation</p>
<p>Django Categories v1.1 documentation</p>
</div>
<div id="header">
<div id="title"><h1>Registering Models</h1></div>
@ -178,7 +175,7 @@
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first last simple">
<tr class="field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first last simple">
<li><strong>model</strong> &#8211; The Django Model to link to Django Categories</li>
<li><strong>field_name</strong> &#8211; Optional name for the field <strong>default:</strong> category</li>
<li><strong>extra_params</strong> &#8211; Optional dictionary of extra parameters passed to the <tt class="docutils literal"><span class="pre">ForeignKey</span></tt> class.</li>
@ -212,7 +209,7 @@
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first last simple">
<tr class="field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first last simple">
<li><strong>model</strong> &#8211; The Django Model to link to Django Categories</li>
<li><strong>field_name</strong> &#8211; Optional name for the field <strong>default:</strong> categories</li>
<li><strong>extra_params</strong> &#8211; Optional dictionary of extra parameters passed to the <tt class="docutils literal"><span class="pre">ManyToManyField</span></tt> class.</li>
@ -238,7 +235,7 @@
<div class="footer">
<p>
&copy; Copyright 2010-2012, Corey Oordt.
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.2.
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.0.7.
</p>
</div>
<div class="clearer"></div>

View file

@ -2,20 +2,17 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Search &mdash; Django Categories 1.0.5 documentation</title>
<title>Search &mdash; Django Categories v1.1 documentation</title>
<link rel="stylesheet" href="_static/default.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: '',
VERSION: '1.0.5',
VERSION: '1.1',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true
@ -25,7 +22,7 @@
<script type="text/javascript" src="_static/underscore.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<script type="text/javascript" src="_static/searchtools.js"></script>
<link rel="top" title="Django Categories 1.0.5 documentation" href="index.html" />
<link rel="top" title="Django Categories v1.1 documentation" href="index.html" />
<script type="text/javascript">
jQuery(function() { Search.loadIndex("searchindex.js"); });
</script>
@ -34,7 +31,7 @@
</head>
<body>
<div id="docstitle">
<p>Django Categories 1.0.5 documentation</p>
<p>Django Categories v1.1 documentation</p>
</div>
<div id="header">
<div id="title"><h1>Search</h1></div>
@ -99,7 +96,7 @@
<div class="footer">
<p>
&copy; Copyright 2010-2012, Corey Oordt.
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.2.
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.0.7.
</p>
</div>
<div class="clearer"></div>

File diff suppressed because one or more lines are too long

View file

@ -2,20 +2,17 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Using categories in templates &mdash; Django Categories 1.0.5 documentation</title>
<title>Using categories in templates &mdash; Django Categories v1.1 documentation</title>
<link rel="stylesheet" href="_static/default.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: '',
VERSION: '1.0.5',
VERSION: '1.1',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true
@ -24,13 +21,13 @@
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/underscore.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<link rel="top" title="Django Categories 1.0.5 documentation" href="index.html" />
<link rel="top" title="Django Categories v1.1 documentation" href="index.html" />
<link rel="next" title="Registering Models" href="registering_models.html" />
<link rel="prev" title="Getting Started" href="getting_started.html" />
</head>
<body>
<div id="docstitle">
<p>Django Categories 1.0.5 documentation</p>
<p>Django Categories v1.1 documentation</p>
</div>
<div id="header">
<div id="title"><h1>Using categories in templates</h1></div>
@ -172,8 +169,8 @@ keys:</p>
<blockquote>
<div><dl class="docutils">
<dt><tt class="docutils literal"><span class="pre">'new_level'</span></tt></dt>
<dd><tt class="docutils literal"><span class="pre">True</span></tt> if the current item is the start of a new level in
the tree, <tt class="docutils literal"><span class="pre">False</span></tt> otherwise.</dd>
<dd><tt class="xref docutils literal"><span class="pre">True</span></tt> if the current item is the start of a new level in
the tree, <tt class="xref docutils literal"><span class="pre">False</span></tt> otherwise.</dd>
<dt><tt class="docutils literal"><span class="pre">'closed_levels'</span></tt></dt>
<dd>A list of levels which end after the current item. This will
be an empty list if the next item&#8217;s level is the same as or
@ -210,7 +207,7 @@ on the right:</p>
<div class="footer">
<p>
&copy; Copyright 2010-2012, Corey Oordt.
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.2.
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.0.7.
</p>
</div>
<div class="clearer"></div>

View file

@ -1,5 +1,7 @@
# Django settings for sample project.
import os, sys
import os
import sys
import django
APP = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
PROJ_ROOT = os.path.abspath(os.path.dirname(__file__))
@ -75,11 +77,6 @@ STATICFILES_FINDERS = (
# 'django.contrib.staticfiles.finders.DefaultStorageFinder',
)
# URL prefix for admin static files -- CSS, JavaScript and images.
# Make sure to use a trailing slash.
# Examples: "http://foo.com/static/admin/", "/static/admin/".
ADMIN_MEDIA_PREFIX = '/static/admin/'
# Make this unique, and don't share it with anybody.
SECRET_KEY = 'bwq#m)-zsey-fs)0#4*o=2z(v5g!ei=zytl9t-1hesh4b&-u^d'
@ -106,37 +103,27 @@ TEMPLATE_DIRS = (
os.path.abspath(os.path.join(os.path.dirname(__file__), 'templates')),
)
INSTALLED_APPS = (
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.messages',
'django.contrib.staticfiles',
'django.contrib.flatpages',
'categories',
'categories.editor',
'mptt',
'simpletext',
'south',
)
CATEGORIES_SETTINGS = {
'ALLOW_SLUG_CHANGE': True,
'RELATION_MODELS': ['simpletext.simpletext','flatpages.flatpage'],
'RELATION_MODELS': ['simpletext.simpletext', 'flatpages.flatpage'],
'FK_REGISTRY': {
'flatpages.flatpage': 'category',
'simpletext.simpletext': (
'primary_category',
'primary_category',
{'name': 'secondary_category', 'related_name': 'simpletext_sec_cat'},
),
},
'M2M_REGISTRY': {
'simpletext.simpletext': {'name': 'categories', 'related_name': 'm2mcats'},
'flatpages.flatpage': (
{'name': 'other_categories', 'related_name': 'other_cats'},
{'name': 'more_categories', 'related_name': 'more_cats'},
{'name': 'other_categories', 'related_name': 'other_cats'},
{'name': 'more_categories', 'related_name': 'more_cats'},
),
},
}
if django.VERSION[1] == 4:
from settings14 import *
if django.VERSION[1] == 3:
from settings13 import *

16
example/settings13.py Normal file
View file

@ -0,0 +1,16 @@
ADMIN_MEDIA_PREFIX = '/static/admin/'
INSTALLED_APPS = (
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.staticfiles',
'django.contrib.flatpages',
'categories',
'categories.editor',
'mptt',
'simpletext',
# 'south',
)

15
example/settings14.py Normal file
View file

@ -0,0 +1,15 @@
INSTALLED_APPS = (
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.messages',
'django.contrib.staticfiles',
'django.contrib.flatpages',
'categories',
'categories.editor',
'mptt',
'simpletext',
# 'south',
)