Skip to content

Commit 579101b

Browse files
committed
Got tests back in working order; documentation updates for Django 1.0
git-svn-id: https://django-tagging.googlecode.com/svn/trunk@151 83e7428b-ec2a-0410-86f2-bf466d0e5e72
1 parent 51533fa commit 579101b

File tree

5 files changed

+68
-124
lines changed

5 files changed

+68
-124
lines changed

docs/overview.txt

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ the command ``svn update`` from within the ``tagging-trunk`` directory.
7676
copy of the source code.
7777

7878
.. _`Subversion`: http://subversion.tigris.org
79-
.. _`PYTHONPATH`: http://docs.python.org/tut/node8.html#SECTION008110000000000000000
79+
.. _`PYTHONPATH`: http://www.python.org/doc/2.5.2/tut/node8.html#SECTION008120000000000000000
8080
.. _`junction`: http://www.microsoft.com/technet/sysinternals/FileAndDisk/Junction.mspx
8181
.. _`CHANGELOG`: http://django-tagging.googlecode.com/svn/trunk/CHANGELOG.txt
8282
.. _`backwards-incompatible changes wiki page`: http://code.google.com/p/django-tagging/wiki/BackwardsIncompatibleChanges
@@ -119,8 +119,7 @@ Default: ``50``
119119

120120
An integer which specifies the maximum length which any tag is allowed
121121
to have. This is used for validation in the ``django.contrib.admin``
122-
application and in any ``newforms`` forms automatically generated using
123-
``ModelForm``.
122+
application and in any forms automatically generated using ``ModelForm``.
124123

125124

126125
Registering your models
@@ -453,7 +452,7 @@ greater than 99::
453452

454453
>>> Tag.objects.usage_for_model(Widget, filters=dict(size__gt=99, user__username='Alan'))
455454

456-
.. _`field lookups`: http://www.djangoproject.com/documentation/db-api/#field-lookups
455+
.. _`field lookups`: http://docs.djangoproject.com/en/dev/topics/db/queries/#field-lookups
457456

458457
**New in development version**
459458

@@ -699,18 +698,17 @@ model::
699698

700699
This field will also validate that it has been given a valid list of
701700
tag names, separated by a single comma, a single space or a comma
702-
followed by a space, using the ``is_tag_list`` validator from
703-
``tagging.validators``.
701+
followed by a space.
704702

705703

706704
Form fields
707705
===========
708706

709707
The ``tagging.forms`` module contains a ``Field`` for use with
710-
Django's `newforms library`_ which takes care of validating tag name
708+
Django's `forms library`_ which takes care of validating tag name
711709
input when used in your forms.
712710

713-
.. _`newforms library`: http://www.djangoproject.com/documentation/newforms/
711+
.. _`forms library`: http://docs.djangoproject.com/en/dev/topics/forms/
714712

715713
Field types
716714
-----------
@@ -722,9 +720,9 @@ A form ``Field`` which is displayed as a single-line text input, which
722720
validates that the input it receives is a valid list of tag names.
723721

724722
When you generate a form for one of your models automatically, using
725-
the ``ModelForm`` class provided by newforms, any
726-
``tagging.fields.TagField`` fields in your model will automatically be
727-
represented by a ``tagging.forms.TagField`` in the generated form.
723+
the ``ModelForm`` class, any ``tagging.fields.TagField`` fields in your
724+
model will automatically be represented by a ``tagging.forms.TagField``
725+
in the generated form.
728726

729727

730728
Generic views
@@ -774,7 +772,7 @@ template context variables which may be provided.
774772

775773
* ``tag``: The ``Tag`` instance for the given tag.
776774

777-
.. _`object_list documentation`: http://www.djangoproject.com/documentation/generic_views/#django-views-generic-list-detail-object-list
775+
.. _`object_list documentation`: http://docs.djangoproject.com/en/dev/ref/generic-views/#django-views-generic-list-detail-object-list
778776

779777
Example usage
780778
~~~~~~~~~~~~~

tagging/forms.py

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,27 @@
11
"""
2-
Tagging components for Django's ``newforms`` form library.
2+
Tagging components for Django's form library.
33
"""
44
from django import forms
55
from django.utils.translation import ugettext as _
66

77
from tagging import settings
88
from tagging.models import Tag
9-
from tagging.validators import is_tag, is_tag_list
109
from tagging.utils import parse_tag_input
1110

1211
class AdminTagForm(forms.ModelForm):
1312
class Meta:
1413
model = Tag
15-
14+
1615
def clean_name(self):
17-
value = self.cleaned_data["name"]
18-
return is_tag(value)
19-
16+
value = self.cleaned_data['name']
17+
tag_names = parse_tag_input(value)
18+
if len(tag_names) > 1:
19+
raise ValidationError(_('Multiple tags were given.'))
20+
elif len(tag_names[0]) > settings.MAX_TAG_LENGTH:
21+
raise forms.ValidationError(
22+
_('A tag may be no more than %s characters long.') %
23+
settings.MAX_TAG_LENGTH)
24+
return value
2025

2126
class TagField(forms.CharField):
2227
"""
@@ -27,4 +32,9 @@ def clean(self, value):
2732
value = super(TagField, self).clean(value)
2833
if value == u'':
2934
return value
30-
return is_tag_list(value)
35+
for tag_name in parse_tag_input(value):
36+
if len(tag_name) > settings.MAX_TAG_LENGTH:
37+
raise forms.ValidationError(
38+
_('Each tag may be no more than %s characters long.') %
39+
settings.MAX_TAG_LENGTH)
40+
return value

tagging/models.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ class TaggedItemManager(models.Manager):
267267
objects we're interested in, then use the ORM's ``__in``
268268
lookup to return a ``QuerySet``.
269269
270-
now that the queryset-refactor branch is in the trunk, this can be
270+
Now that the queryset-refactor branch is in the trunk, this can be
271271
tidied up significantly.
272272
"""
273273
def get_by_model(self, queryset_or_model, tags):
@@ -419,11 +419,16 @@ def get_related(self, obj, queryset_or_model, num=None):
419419
'tag': qn(self.model._meta.get_field('tag').rel.to._meta.db_table),
420420
'content_type_id': content_type.pk,
421421
'related_content_type_id': related_content_type.pk,
422-
'limit_offset': num is not None and connection.ops.limit_offset_sql(num) or '',
422+
# Hardcoding this for now just to get tests working again - this
423+
# should now be handled by the query object.
424+
'limit_offset': num is not None and 'LIMIT %s' or '',
423425
}
424426

425427
cursor = connection.cursor()
426-
cursor.execute(query, [obj.pk])
428+
params = [obj.pk]
429+
if num is not None:
430+
params.append(num)
431+
cursor.execute(query, params)
427432
object_ids = [row[0] for row in cursor.fetchall()]
428433
if len(object_ids) > 0:
429434
# Use in_bulk here instead of an id__in lookup, because id__in would

tagging/tests/tests.py

Lines changed: 33 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
# -*- coding: utf-8 -*-
2-
tests = r"""
2+
r"""
33
>>> import os
4-
>>> from django import newforms as forms
4+
>>> from django import forms
5+
>>> from django.db.models import Q
56
>>> from tagging.forms import TagField
67
>>> from tagging import settings
78
>>> from tagging.models import Tag, TaggedItem
89
>>> from tagging.tests.models import Article, Link, Perch, Parrot, FormTest
910
>>> from tagging.utils import calculate_cloud, get_tag_list, get_tag, parse_tag_input
1011
>>> from tagging.utils import LINEAR
11-
>>> from tagging.validators import is_tag_list, is_tag
1212
1313
#############
1414
# Utilities #
@@ -152,24 +152,6 @@
152152
...
153153
ValueError: Invalid distribution algorithm specified: cheese.
154154
155-
# Validators ##################################################################
156-
157-
>>> is_tag_list('foo qwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbn bar', {})
158-
Traceback (most recent call last):
159-
...
160-
ValidationError: [u'Each tag may be no more than 50 characters long.']
161-
162-
>>> is_tag('"test"', {})
163-
>>> is_tag(',test', {})
164-
>>> is_tag('f o o', {})
165-
Traceback (most recent call last):
166-
...
167-
ValidationError: [u'Multiple tags were given.']
168-
>>> is_tag_list('foo qwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbn bar', {})
169-
Traceback (most recent call last):
170-
...
171-
ValidationError: [u'Each tag may be no more than 50 characters long.']
172-
173155
###########
174156
# Tagging #
175157
###########
@@ -393,6 +375,36 @@
393375
>>> TaggedItem.objects.get_related(a1, Link)
394376
[]
395377
378+
# Limiting results to a queryset
379+
>>> [(tag.name, tag.count) for tag in Tag.objects.usage_for_queryset(Parrot.objects.filter(state='no more'), counts=True)]
380+
[(u'foo', 1), (u'ter', 1)]
381+
>>> [(tag.name, tag.count) for tag in Tag.objects.usage_for_queryset(Parrot.objects.filter(state__startswith='p'), counts=True)]
382+
[(u'bar', 2), (u'baz', 1), (u'foo', 1), (u'ter', 1)]
383+
>>> [(tag.name, tag.count) for tag in Tag.objects.usage_for_queryset(Parrot.objects.filter(perch__size__gt=4), counts=True)]
384+
[(u'bar', 2), (u'baz', 1), (u'foo', 1), (u'ter', 1)]
385+
>>> [(tag.name, tag.count) for tag in Tag.objects.usage_for_queryset(Parrot.objects.filter(perch__smelly=True), counts=True)]
386+
[(u'bar', 1), (u'foo', 2), (u'ter', 1)]
387+
>>> [(tag.name, tag.count) for tag in Tag.objects.usage_for_queryset(Parrot.objects.filter(perch__smelly=True), min_count=2)]
388+
[(u'foo', 2)]
389+
>>> [(tag.name, hasattr(tag, 'counts')) for tag in Tag.objects.usage_for_queryset(Parrot.objects.filter(perch__size__gt=4))]
390+
[(u'bar', False), (u'baz', False), (u'foo', False), (u'ter', False)]
391+
>>> [(tag.name, hasattr(tag, 'counts')) for tag in Tag.objects.usage_for_queryset(Parrot.objects.filter(perch__size__gt=99))]
392+
[]
393+
>>> [(tag.name, tag.count) for tag in Tag.objects.usage_for_queryset(Parrot.objects.filter(Q(perch__size__gt=6) | Q(state__startswith='l')), counts=True)]
394+
[(u'bar', 2), (u'foo', 1), (u'ter', 1)]
395+
>>> [(tag.name, tag.count) for tag in Tag.objects.usage_for_queryset(Parrot.objects.filter(Q(perch__size__gt=6) | Q(state__startswith='l')), min_count=2)]
396+
[(u'bar', 2)]
397+
>>> [(tag.name, hasattr(tag, 'counts')) for tag in Tag.objects.usage_for_queryset(Parrot.objects.filter(Q(perch__size__gt=6) | Q(state__startswith='l')))]
398+
[(u'bar', False), (u'foo', False), (u'ter', False)]
399+
>>> [(tag.name, tag.count) for tag in Tag.objects.usage_for_queryset(Parrot.objects.exclude(state='passed on'), counts=True)]
400+
[(u'bar', 2), (u'foo', 2), (u'ter', 2)]
401+
>>> [(tag.name, tag.count) for tag in Tag.objects.usage_for_queryset(Parrot.objects.exclude(state__startswith='p'), min_count=2)]
402+
[(u'ter', 2)]
403+
>>> [(tag.name, tag.count) for tag in Tag.objects.usage_for_queryset(Parrot.objects.exclude(Q(perch__size__gt=6) | Q(perch__smelly=False)), counts=True)]
404+
[(u'foo', 1), (u'ter', 1)]
405+
>>> [(tag.name, tag.count) for tag in Tag.objects.usage_for_queryset(Parrot.objects.exclude(perch__smelly=True).filter(state__startswith='l'), counts=True)]
406+
[(u'bar', 1), (u'ter', 1)]
407+
396408
################
397409
# Model Fields #
398410
################
@@ -444,52 +456,3 @@
444456
...
445457
ValidationError: [u'Each tag may be no more than 50 characters long.']
446458
"""
447-
448-
tests_pre_qsrf = tests + r"""
449-
# Limiting results to a queryset
450-
>>> Tag.objects.usage_for_queryset(Parrot.objects.filter())
451-
Traceback (most recent call last):
452-
...
453-
AttributeError: 'TagManager.usage_for_queryset' is not compatible with pre-queryset-refactor versions of Django.
454-
"""
455-
456-
tests_post_qsrf = tests + r"""
457-
>>> from django.db.models import Q
458-
459-
# Limiting results to a queryset
460-
>>> [(tag.name, tag.count) for tag in Tag.objects.usage_for_queryset(Parrot.objects.filter(state='no more'), counts=True)]
461-
[(u'foo', 1), (u'ter', 1)]
462-
>>> [(tag.name, tag.count) for tag in Tag.objects.usage_for_queryset(Parrot.objects.filter(state__startswith='p'), counts=True)]
463-
[(u'bar', 2), (u'baz', 1), (u'foo', 1), (u'ter', 1)]
464-
>>> [(tag.name, tag.count) for tag in Tag.objects.usage_for_queryset(Parrot.objects.filter(perch__size__gt=4), counts=True)]
465-
[(u'bar', 2), (u'baz', 1), (u'foo', 1), (u'ter', 1)]
466-
>>> [(tag.name, tag.count) for tag in Tag.objects.usage_for_queryset(Parrot.objects.filter(perch__smelly=True), counts=True)]
467-
[(u'bar', 1), (u'foo', 2), (u'ter', 1)]
468-
>>> [(tag.name, tag.count) for tag in Tag.objects.usage_for_queryset(Parrot.objects.filter(perch__smelly=True), min_count=2)]
469-
[(u'foo', 2)]
470-
>>> [(tag.name, hasattr(tag, 'counts')) for tag in Tag.objects.usage_for_queryset(Parrot.objects.filter(perch__size__gt=4))]
471-
[(u'bar', False), (u'baz', False), (u'foo', False), (u'ter', False)]
472-
>>> [(tag.name, hasattr(tag, 'counts')) for tag in Tag.objects.usage_for_queryset(Parrot.objects.filter(perch__size__gt=99))]
473-
[]
474-
>>> [(tag.name, tag.count) for tag in Tag.objects.usage_for_queryset(Parrot.objects.filter(Q(perch__size__gt=6) | Q(state__startswith='l')), counts=True)]
475-
[(u'bar', 2), (u'foo', 1), (u'ter', 1)]
476-
>>> [(tag.name, tag.count) for tag in Tag.objects.usage_for_queryset(Parrot.objects.filter(Q(perch__size__gt=6) | Q(state__startswith='l')), min_count=2)]
477-
[(u'bar', 2)]
478-
>>> [(tag.name, hasattr(tag, 'counts')) for tag in Tag.objects.usage_for_queryset(Parrot.objects.filter(Q(perch__size__gt=6) | Q(state__startswith='l')))]
479-
[(u'bar', False), (u'foo', False), (u'ter', False)]
480-
>>> [(tag.name, tag.count) for tag in Tag.objects.usage_for_queryset(Parrot.objects.exclude(state='passed on'), counts=True)]
481-
[(u'bar', 2), (u'foo', 2), (u'ter', 2)]
482-
>>> [(tag.name, tag.count) for tag in Tag.objects.usage_for_queryset(Parrot.objects.exclude(state__startswith='p'), min_count=2)]
483-
[(u'ter', 2)]
484-
>>> [(tag.name, tag.count) for tag in Tag.objects.usage_for_queryset(Parrot.objects.exclude(Q(perch__size__gt=6) | Q(perch__smelly=False)), counts=True)]
485-
[(u'foo', 1), (u'ter', 1)]
486-
>>> [(tag.name, tag.count) for tag in Tag.objects.usage_for_queryset(Parrot.objects.exclude(perch__smelly=True).filter(state__startswith='l'), counts=True)]
487-
[(u'bar', 1), (u'ter', 1)]
488-
"""
489-
490-
try:
491-
from django.db.models.query import parse_lookup
492-
except ImportError:
493-
__test__ = {'post-qsrf': tests_post_qsrf}
494-
else:
495-
__test__ = {'pre-qsrf': tests_pre_qsrf}

tagging/validators.py

Lines changed: 0 additions & 32 deletions
This file was deleted.

0 commit comments

Comments
 (0)