Commit 3c27a56b by Alex Gaynor

Resolve merge conflicts

parents ea52a9f1 3e130b2e
Changelog
=========
master (unreleased)
~~~~~~~~~~~~~~~~~~~
0.8.0
~~~~~
* Fixed querying for objects using ``exclude(tags__in=tags)``.
* Marked strings as translatable.
* Added a Russian translation.
* Created a `mailing list <http://groups.google.com/group/django-taggit>`_.
* Smarter tagstring parsing for form field; ported from Jonathan
Buchanan's `django-tagging
<http://django-tagging.googlecode.com>`_. Now supports tags
containing commas. See :ref:`tags-in-forms` for details.
* Switched to using savepoints around the slug generation for tags. This
ensures that it works fine on databases (such as Postgres) which dirty a
transaction with an ``IntegrityError``.
* Added Python 2.4 compatibility.
* Added Django 1.1 compatibility.
* Smarter tagstring parsing for form field; ported from Jonathan
Buchanan's `django-tagging
<http://django-tagging.googlecode.com>`_. Now supports tags
containing commas. See :ref:`tags-in-forms` for details.
......@@ -45,9 +45,9 @@ copyright = u'2010, Alex Gaynor'
# built documents.
#
# The short X.Y version.
version = '0.6'
version = '0.8'
# The full version, including alpha/beta/rc tags.
release = '0.6'
release = '0.8.0'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
......
VERSION = (0, 6, 0)
VERSION = (0, 8, 0)
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: Django Taggit\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2010-06-11 11:28+0700\n"
"PO-Revision-Date: 2010-06-11 11:30+0700\n"
"Last-Translator: Igor 'idle sign' Starikov <idlesign@yandex.ru>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
"X-Poedit-Language: Russian\n"
#: forms.py:20
msgid "Please provide a comma-separated list of tags."
msgstr "Укажите метки через запятую."
#: managers.py:41
#: managers.py:101
#: models.py:17
msgid "Tags"
msgstr "Метки"
#: managers.py:102
msgid "A comma-separated list of tags."
msgstr "Список меток через запятую."
#: models.py:9
msgid "Name"
msgstr "Название"
#: models.py:10
msgid "Slug"
msgstr "Слаг"
#: models.py:16
msgid "Tag"
msgstr "Метка"
#: models.py:55
#, python-format
msgid "%(object)s tagged with %(tag)s"
msgstr "элемент «%(object)s» с меткой «%(tag)s»"
#: models.py:82
msgid "Object id"
msgstr "ID объекта"
#: models.py:83
msgid "Content type"
msgstr "Тип содержимого"
#: models.py:87
msgid "Tagged Item"
msgstr "Элемент с меткой"
#: models.py:88
msgid "Tagged Items"
msgstr "Элементы с меткой"
#: contrib/suggest/models.py:57
msgid "Enter a valid Regular Expression. To make it case-insensitive include \"(?i)\" in your expression."
msgstr "Введите регулярное выражение. Чтобы сделать его чувствительным к регистру укажите \"(?i)\"."
......@@ -49,6 +49,7 @@ class TaggableManager(object):
self.db_column = None
self.choices = None
self.serialize = False
self.null = True
self.creation_counter = models.Field.creation_counter
models.Field.creation_counter += 1
......@@ -79,7 +80,7 @@ class TaggableManager(object):
"help_text": _("A comma-separated list of tags.")
}
defaults.update(kwargs)
return form_class(**kwargs)
return form_class(**defaults)
def value_from_object(self, instance):
if instance.pk:
......
......@@ -3,15 +3,20 @@ from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes.generic import GenericForeignKey
from django.db import models, IntegrityError, transaction
from django.template.defaultfilters import slugify
from django.utils.translation import ugettext_lazy as _, ugettext
class Tag(models.Model):
name = models.CharField(max_length=100)
slug = models.SlugField(unique=True, max_length=100)
name = models.CharField(verbose_name=_('Name'), max_length=100)
slug = models.SlugField(verbose_name=_('Slug'), unique=True, max_length=100)
def __unicode__(self):
return self.name
class Meta:
verbose_name = _("Tag")
verbose_name_plural = _("Tags")
def save(self, *args, **kwargs):
if not self.pk and not self.slug:
self.slug = slug = slugify(self.name)
......@@ -48,7 +53,10 @@ class TaggedItemBase(models.Model):
tag = models.ForeignKey(Tag, related_name="%(app_label)s_%(class)s_items")
def __unicode__(self):
return u"%s tagged with %s" % (self.content_object, self.tag)
return ugettext("%(object)s tagged with %(tag)s") % {
"object": self.content_object,
"tag": self.tag
}
class Meta:
abstract = True
......@@ -75,10 +83,15 @@ class TaggedItemBase(models.Model):
class TaggedItem(TaggedItemBase):
object_id = models.IntegerField()
content_type = models.ForeignKey(ContentType, related_name="tagged_items")
object_id = models.IntegerField(verbose_name=_('Object id'))
content_type = models.ForeignKey(ContentType, verbose_name=_('Content type'),
related_name="tagged_items")
content_object = GenericForeignKey()
class Meta:
verbose_name = _("Tagged Item")
verbose_name_plural = _("Tagged Items")
@classmethod
def lookup_kwargs(cls, instance):
return {
......
......@@ -15,6 +15,10 @@ class Pet(models.Model):
name = models.CharField(max_length=50)
tags = TaggableManager()
def __unicode__(self):
return self.name
class HousePet(Pet):
trained = models.BooleanField()
......@@ -36,6 +40,10 @@ class DirectPet(models.Model):
name = models.CharField(max_length=50)
tags = TaggableManager(through=TaggedPet)
def __unicode__(self):
return self.name
class DirectHousePet(DirectPet):
trained = models.BooleanField()
......@@ -60,6 +68,9 @@ class CustomPKPet(models.Model):
name = models.CharField(max_length=50, primary_key=True)
tags = TaggableManager(through=TaggedCustomPKPet)
def __unicode__(self):
return self.name
class CustomPKHousePet(CustomPKPet):
trained = models.BooleanField()
......@@ -137,6 +137,20 @@ class TaggableManagerTestCase(BaseTaggingTestCase):
map(lambda o: o.pk, self.pet_model.objects.filter(tags__name__in=["fuzzy"])),
[kitty.pk, cat.pk]
)
def test_exclude(self):
apple = self.food_model.objects.create(name="apple")
apple.tags.add("red", "green", "delicious")
pear = self.food_model.objects.create(name="pear")
pear.tags.add("green", "delicious")
guava = self.food_model.objects.create(name="guava")
self.assertEqual(
map(lambda o: o.pk, self.food_model.objects.exclude(tags__in=["red"])),
[pear.pk, guava.pk],
)
def test_similarity_by_tag(self):
"""Test that pears are more similar to apples than watermelons"""
......@@ -168,6 +182,16 @@ class TaggableManagerTestCase(BaseTaggingTestCase):
# [i.tag for i in self.taggeditem_model.objects.filter(**lookup_kwargs)],
# ['scary']
# )
def test_taggeditem_unicode(self):
ross = self.pet_model.objects.create(name="ross")
# I keep Ross Perot for a pet, what's it to you?
ross.tags.add("president")
self.assertEqual(
unicode(self.taggeditem_model.objects.all()[0]),
"ross tagged with president"
)
class TaggableManagerDirectTestCase(TaggableManagerTestCase):
......@@ -195,7 +219,7 @@ class TaggableFormTestCase(BaseTaggingTestCase):
self.assertEqual(self.form_class.base_fields.keys(), ['name', 'tags'])
f = self.form_class({'name': 'apple', 'tags': 'green, red, yummy'})
self.assertEqual(str(f), """<tr><th><label for="id_name">Name:</label></th><td><input id="id_name" type="text" name="name" value="apple" maxlength="50" /></td></tr>\n<tr><th><label for="id_tags">Tags:</label></th><td><input type="text" name="tags" value="green, red, yummy" id="id_tags" /></td></tr>""")
self.assertEqual(str(f), """<tr><th><label for="id_name">Name:</label></th><td><input id="id_name" type="text" name="name" value="apple" maxlength="50" /></td></tr>\n<tr><th><label for="id_tags">Tags:</label></th><td><input type="text" name="tags" value="green, red, yummy" id="id_tags" /><br />A comma-separated list of tags.</td></tr>""")
f.save()
apple = self.food_model.objects.get(name='apple')
self.assert_tags_equal(apple.tags.all(), ['green', 'red', 'yummy'])
......@@ -211,11 +235,11 @@ class TaggableFormTestCase(BaseTaggingTestCase):
self.assert_tags_equal(raspberry.tags.all(), [])
f = self.form_class(instance=apple)
self.assertEqual(str(f), """<tr><th><label for="id_name">Name:</label></th><td><input id="id_name" type="text" name="name" value="apple" maxlength="50" /></td></tr>\n<tr><th><label for="id_tags">Tags:</label></th><td><input type="text" name="tags" value="delicious green red yummy" id="id_tags" /></td></tr>""")
self.assertEqual(str(f), """<tr><th><label for="id_name">Name:</label></th><td><input id="id_name" type="text" name="name" value="apple" maxlength="50" /></td></tr>\n<tr><th><label for="id_tags">Tags:</label></th><td><input type="text" name="tags" value="delicious green red yummy" id="id_tags" /><br />A comma-separated list of tags.</td></tr>""")
apple.tags.add('has,comma')
f = self.form_class(instance=apple)
self.assertEqual(str(f), """<tr><th><label for="id_name">Name:</label></th><td><input id="id_name" type="text" name="name" value="apple" maxlength="50" /></td></tr>\n<tr><th><label for="id_tags">Tags:</label></th><td><input type="text" name="tags" value="&quot;has,comma&quot; delicious green red yummy" id="id_tags" /></td></tr>""")
self.assertEqual(str(f), """<tr><th><label for="id_name">Name:</label></th><td><input id="id_name" type="text" name="name" value="apple" maxlength="50" /></td></tr>\n<tr><th><label for="id_tags">Tags:</label></th><td><input type="text" name="tags" value="&quot;has,comma&quot; delicious green red yummy" id="id_tags" /><br />A comma-separated list of tags.</td></tr>""")
class TaggableFormDirectTestCase(TaggableFormTestCase):
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment