Template tags now work with any derivative of CategoryBase. Recognizes the "using" param to specify the model to use.

This commit is contained in:
Corey Oordt 2012-07-12 19:28:11 -04:00
parent 86d9b376e1
commit 3a71754a6a
4 changed files with 76 additions and 49 deletions

View file

@ -1,18 +1,17 @@
from django import template
from django.db.models import get_model
from django.template import (Node, TemplateSyntaxError, Variable,
VariableDoesNotExist)
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, recursetree,
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(recursetree)
register.tag("full_tree_for_category", full_tree_for_model)
@ -72,7 +71,7 @@ def get_category(category_string, model=Category):
class CategoryDrillDownNode(template.Node):
def __init__(self, category, varname, model):
self.category = template.Variable(category)
self.category = category
self.varname = varname
self.model = model
@ -133,7 +132,7 @@ def get_category_drilldown(parser, token):
if bits[2] == 'using':
varname = bits[5].strip("'\"")
model = bits[3].strip("'\"")
category = bits[1]
category = FilterExpression(bits[1], parser)
return CategoryDrillDownNode(category, varname, model)
@ -282,12 +281,12 @@ class LatestObjectsNode(Node):
"""
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)
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 render(self, context):
@ -323,19 +322,19 @@ def do_get_latest_objects_by_category(parser, token):
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
num = FilterExpression(None, parser)
return LatestObjectsNode(var_name, category, app_label, model_name, set_name,
date_field, num)
@ -376,3 +375,35 @@ def tree_queryset(value):
qs = qs.distinct()
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

@ -58,11 +58,10 @@ class CategoryTagsTest(TestCase):
self.assertEqual(resp, expected_resp)
# recursetree
expected_resp = u'<ul><li><a href="/categories/">Top</a><ul><li><a href="/categories/world/">World</a></li></ul></li></ul>'
ctxt = {'nodes': Category.objects.filter(name__in=("Worldbeat", "Urban cowboy"))}
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 class="root">{% recursetree nodes|treeinfo %}<li>{{ node.name }}'
'{% if not node.is_leaf_node %}<ul class="children">{{ children }}'
'<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)