[Python-modules-commits] [django-taggit] 01/03: Imported Upstream version 0.17.4
Michal Cihar
nijel at moszumanska.debian.org
Fri Nov 27 07:42:11 UTC 2015
This is an automated email from the git hooks/post-receive script.
nijel pushed a commit to branch master
in repository django-taggit.
commit 034a73194e7202334134b01b1208fc679e7dd1f2
Author: Michal Čihař <nijel at debian.org>
Date: Fri Nov 27 08:36:45 2015 +0100
Imported Upstream version 0.17.4
---
CHANGELOG.txt | 5 +++
PKG-INFO | 2 +-
django_taggit.egg-info/PKG-INFO | 2 +-
docs/custom_tagging.txt | 84 +++++++++++++++++++++++++++++++++++-----
taggit/__init__.py | 2 +-
taggit/managers.py | 6 +--
taggit/models.py | 20 +++++++++-
tests/forms.py | 8 +++-
tests/migrations/0001_initial.py | 61 +++++++++++++++++++++++++++--
tests/models.py | 38 +++++++++++++++---
tests/tests.py | 31 ++++++++++++---
11 files changed, 226 insertions(+), 33 deletions(-)
diff --git a/CHANGELOG.txt b/CHANGELOG.txt
index 854abb0..f9520c3 100644
--- a/CHANGELOG.txt
+++ b/CHANGELOG.txt
@@ -1,6 +1,11 @@
Changelog
=========
+0.17.4 (2015-11-25)
+~~~~~~~~~~~~~~~~~~~
+ * Allows custom Through Model with GenericForeignKey
+ * https://github.com/alex/django-taggit/pull/359
+
0.17.3 (2015-10-26)
~~~~~~~~~~~~~~~~~~~
* Silence Django 1.9 warning about on_delete
diff --git a/PKG-INFO b/PKG-INFO
index 39a0a00..dfe9886 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: django-taggit
-Version: 0.17.3
+Version: 0.17.4
Summary: django-taggit is a reusable Django application for simple tagging.
Home-page: http://github.com/alex/django-taggit/tree/master
Author: Alex Gaynor
diff --git a/django_taggit.egg-info/PKG-INFO b/django_taggit.egg-info/PKG-INFO
index 39a0a00..dfe9886 100644
--- a/django_taggit.egg-info/PKG-INFO
+++ b/django_taggit.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: django-taggit
-Version: 0.17.3
+Version: 0.17.4
Summary: django-taggit is a reusable Django application for simple tagging.
Home-page: http://github.com/alex/django-taggit/tree/master
Author: Alex Gaynor
diff --git a/docs/custom_tagging.txt b/docs/custom_tagging.txt
index f85ceba..87ff286 100644
--- a/docs/custom_tagging.txt
+++ b/docs/custom_tagging.txt
@@ -10,6 +10,22 @@ want to store additional data about a tag, such as whether it is official. In
these cases ``django-taggit`` makes it easy to substitute your own through
model, or ``Tag`` model.
+To change the behavior there are a number of classes you can subclass to obtain
+different behavior:
+
+=============================== =======================================================================
+Class name Behavior
+=============================== =======================================================================
+``TaggedItemBase`` Allows custom ``ForeignKeys`` to models.
+``GenericTaggedItemBase`` Allows custom ``Tag`` models. Tagged models use an integer primary key.
+``GenericUUIDTaggedItemBase`` Allows custom ``Tag`` models. Tagged models use a UUID primary key.
+``CommonGenericTaggedItemBase`` Allows custom ``Tag`` models and ``GenericForeignKeys`` to models.
+``ItemBase`` Allows custom ``Tag`` models and ``ForeignKeys`` to models.
+=============================== =======================================================================
+
+Custom ForeignKeys
+~~~~~~~~~~~~~~~~~~
+
Your intermediary model must be a subclass of
``taggit.models.TaggedItemBase`` with a foreign key to your content
model named ``content_object``. Pass this intermediary model as the
@@ -32,16 +48,66 @@ model named ``content_object``. Pass this intermediary model as the
Once this is done, the API works the same as for GFK-tagged models.
-To change the behavior in other ways there are a number of other classes you
-can subclass to obtain different behavior:
+Custom GenericForeignKeys
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The default ``GenericForeignKey`` used by ``django-taggit`` assume your
+tagged object use an integer primary key. For non-integer primary key,
+your intermediary model must be a subclass of ``taggit.models.CommonGenericTaggedItemBase``
+with a field named ``"object_id"`` of the type of your primary key.
+
+For example, if your primary key is a string::
+
+ from django.db import models
+
+ from taggit.managers import TaggableManager
+ from taggit.models import CommonGenericTaggedItemBase, TaggedItemBase
+
+ class GenericStringTaggedItem(CommonGenericTaggedItemBase, TaggedItemBase):
+ object_id = models.CharField(max_length=50, verbose_name=_('Object id'), db_index=True)
+
+ class Food(models.Model):
+ food_id = models.CharField(primary_key=True)
+ # ... fields here
+
+ tags = TaggableManager(through=GenericStringTaggedItem)
+
+GenericUUIDTaggedItemBase
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. note::
+
+ ``GenericUUIDTaggedItemBase`` relies on Django UUIDField introduced with
+ Django 1.8. Therefore ``GenericUUIDTaggedItemBase`` is only defined
+ if you are using Django 1.8+.
+
+A common use case of a non-integer primary key, is UUID primary key.
+``django-taggit`` provides a base class ``GenericUUIDTaggedItemBase`` ready
+to use with models using an UUID primary key::
+
+ from django.db import models
+ from django.utils.translation import ugettext_lazy as _
+
+ from taggit.managers import TaggableManager
+ from taggit.models import GenericUUIDTaggedItemBase, TaggedItemBase
+
+ class UUIDTaggedItem(GenericUUIDTaggedItemBase, TaggedItemBase):
+ # If you only inherit GenericUUIDTaggedItemBase, you need to define
+ # a tag field. e.g.
+ # tag = models.ForeignKey(Tag, related_name="uuid_tagged_items", on_delete=models.CASCADE)
+
+ class Meta:
+ verbose_name = _("Tag")
+ verbose_name_plural = _("Tags")
+
+ class Food(models.Model):
+ id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
+ # ... fields here
+
+ tags = TaggableManager(through=UUIDTaggedItem)
-========================= ===========================================================
-Class name Behavior
-========================= ===========================================================
-``TaggedItemBase`` Allows custom ``ForeignKeys`` to models.
-``GenericTaggedItemBase`` Allows custom ``Tag`` models.
-``ItemBase`` Allows custom ``Tag`` models and ``ForeignKeys`` to models.
-========================= ===========================================================
+Custom tag
+~~~~~~~~~~
When providing a custom ``Tag`` model it should be a ``ForeignKey`` to your tag
model named ``"tag"``:
diff --git a/taggit/__init__.py b/taggit/__init__.py
index 01433dd..fb92fdc 100644
--- a/taggit/__init__.py
+++ b/taggit/__init__.py
@@ -1 +1 @@
-VERSION = (0, 17, 3)
+VERSION = (0, 17, 4)
diff --git a/taggit/managers.py b/taggit/managers.py
index 9c2f066..350ab1c 100644
--- a/taggit/managers.py
+++ b/taggit/managers.py
@@ -26,7 +26,7 @@ from django.utils.text import capfirst
from django.utils.translation import ugettext_lazy as _
from taggit.forms import TagField
-from taggit.models import GenericTaggedItemBase, TaggedItem
+from taggit.models import CommonGenericTaggedItemBase, TaggedItem
from taggit.utils import _get_field, require_instance_manager
try:
@@ -124,7 +124,7 @@ class _TaggableManager(models.Manager):
from django.db import connections
db = self._db or router.db_for_read(instance.__class__, instance=instance)
- fieldname = ('object_id' if issubclass(self.through, GenericTaggedItemBase)
+ fieldname = ('object_id' if issubclass(self.through, CommonGenericTaggedItemBase)
else 'content_object')
fk = self.through._meta.get_field(fieldname)
query = {
@@ -392,7 +392,7 @@ class TaggableManager(RelatedField, Field):
self.related = RelatedObject(cls, self.model, self)
self.use_gfk = (
- self.through is None or issubclass(self.through, GenericTaggedItemBase)
+ self.through is None or issubclass(self.through, CommonGenericTaggedItemBase)
)
# rel.to renamed to remote_field.model in Django 1.9
diff --git a/taggit/models.py b/taggit/models.py
index 55b4230..4e86658 100644
--- a/taggit/models.py
+++ b/taggit/models.py
@@ -1,6 +1,7 @@
from __future__ import unicode_literals
import django
+from django import VERSION
from django.contrib.contenttypes.models import ContentType
from django.db import IntegrityError, models, transaction
from django.db.models.query import QuerySet
@@ -151,8 +152,7 @@ class TaggedItemBase(ItemBase):
return cls.tag_model().objects.filter(**kwargs).distinct()
-class GenericTaggedItemBase(ItemBase):
- object_id = models.IntegerField(verbose_name=_('Object id'), db_index=True)
+class CommonGenericTaggedItemBase(ItemBase):
content_type = models.ForeignKey(
ContentType,
on_delete=models.CASCADE,
@@ -199,6 +199,22 @@ class GenericTaggedItemBase(ItemBase):
return cls.tag_model().objects.filter(**kwargs).distinct()
+class GenericTaggedItemBase(CommonGenericTaggedItemBase):
+ object_id = models.IntegerField(verbose_name=_('Object id'), db_index=True)
+
+ class Meta:
+ abstract = True
+
+
+if VERSION >= (1, 8):
+
+ class GenericUUIDTaggedItemBase(CommonGenericTaggedItemBase):
+ object_id = models.UUIDField(verbose_name=_('Object id'), db_index=True)
+
+ class Meta:
+ abstract = True
+
+
class TaggedItem(GenericTaggedItemBase, TaggedItemBase):
class Meta:
verbose_name = _("Tagged Item")
diff --git a/tests/forms.py b/tests/forms.py
index 4c6baca..4513389 100644
--- a/tests/forms.py
+++ b/tests/forms.py
@@ -2,7 +2,8 @@ from __future__ import absolute_import, unicode_literals
from django import forms, VERSION
-from .models import CustomPKFood, DirectFood, Food, OfficialFood
+from .models import (CustomPKFood, DirectCustomPKFood, DirectFood, Food,
+ OfficialFood)
fields = None
if VERSION >= (1, 6):
@@ -19,6 +20,11 @@ class DirectFoodForm(forms.ModelForm):
model = DirectFood
fields = fields
+class DirectCustomPKFoodForm(forms.ModelForm):
+ class Meta:
+ model = DirectCustomPKFood
+ fields = fields
+
class CustomPKFoodForm(forms.ModelForm):
class Meta:
model = CustomPKFood
diff --git a/tests/migrations/0001_initial.py b/tests/migrations/0001_initial.py
index 9f14cf7..85d86c2 100644
--- a/tests/migrations/0001_initial.py
+++ b/tests/migrations/0001_initial.py
@@ -62,6 +62,34 @@ class Migration(migrations.Migration):
bases=('tests.custompkpet',),
),
migrations.CreateModel(
+ name='DirectCustomPKFood',
+ fields=[
+ ('name', models.CharField(help_text='', max_length=50, serialize=False, primary_key=True)),
+ ],
+ options={
+ },
+ bases=(models.Model,),
+ ),
+ migrations.CreateModel(
+ name='DirectCustomPKPet',
+ fields=[
+ ('name', models.CharField(help_text='', max_length=50, serialize=False, primary_key=True)),
+ ],
+ options={
+ },
+ bases=(models.Model,),
+ ),
+ migrations.CreateModel(
+ name='DirectCustomPKHousePet',
+ fields=[
+ ('directcustompkpet_ptr', models.OneToOneField(parent_link=True, auto_created=True, primary_key=True, serialize=False, to='tests.DirectCustomPKPet', help_text='')),
+ ('trained', models.BooleanField(default=False, help_text='')),
+ ],
+ options={
+ },
+ bases=('tests.directcustompkpet',),
+ ),
+ migrations.CreateModel(
name='DirectFood',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, help_text='', verbose_name='ID')),
@@ -238,10 +266,23 @@ class Migration(migrations.Migration):
bases=(models.Model,),
),
migrations.CreateModel(
+ name='TaggedCustomPK',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, help_text='', verbose_name='ID')),
+ ('object_id', models.CharField(help_text='', max_length=50, verbose_name='Object id', db_index=True)),
+ ('content_type', models.ForeignKey(related_name='tests_taggedcustompk_tagged_items', verbose_name='Content type', to='contenttypes.ContentType', help_text='', on_delete=models.CASCADE)),
+ ('tag', models.ForeignKey(related_name='tests_taggedcustompk_items', to='taggit.Tag', help_text='')),
+ ],
+ options={
+ 'abstract': False,
+ },
+ bases=(models.Model,),
+ ),
+ migrations.CreateModel(
name='TaggedCustomPKFood',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, help_text='', verbose_name='ID')),
- ('content_object', models.ForeignKey(help_text='', to='tests.CustomPKFood')),
+ ('content_object', models.ForeignKey(help_text='', to='tests.DirectCustomPKFood')),
('tag', models.ForeignKey(related_name='tests_taggedcustompkfood_items', to='taggit.Tag', help_text='')),
],
options={
@@ -253,7 +294,7 @@ class Migration(migrations.Migration):
name='TaggedCustomPKPet',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, help_text='', verbose_name='ID')),
- ('content_object', models.ForeignKey(help_text='', to='tests.CustomPKPet')),
+ ('content_object', models.ForeignKey(help_text='', to='tests.DirectCustomPKPet')),
('tag', models.ForeignKey(related_name='tests_taggedcustompkpet_items', to='taggit.Tag', help_text='')),
],
options={
@@ -365,6 +406,18 @@ class Migration(migrations.Migration):
preserve_default=True,
),
migrations.AddField(
+ model_name='custompkpet',
+ name='tags',
+ field=taggit.managers.TaggableManager(to='taggit.Tag', through='tests.TaggedCustomPK', help_text='A comma-separated list of tags.', verbose_name='Tags'),
+ preserve_default=True,
+ ),
+ migrations.AddField(
+ model_name='custompkfood',
+ name='tags',
+ field=taggit.managers.TaggableManager(to='taggit.Tag', through='tests.TaggedCustomPK', help_text='A comma-separated list of tags.', verbose_name='Tags'),
+ preserve_default=True,
+ ),
+ migrations.AddField(
model_name='directpet',
name='tags',
field=taggit.managers.TaggableManager(to='taggit.Tag', through='tests.TaggedPet', help_text='A comma-separated list of tags.', verbose_name='Tags'),
@@ -377,13 +430,13 @@ class Migration(migrations.Migration):
preserve_default=True,
),
migrations.AddField(
- model_name='custompkpet',
+ model_name='directcustompkpet',
name='tags',
field=taggit.managers.TaggableManager(to='taggit.Tag', through='tests.TaggedCustomPKPet', help_text='A comma-separated list of tags.', verbose_name='Tags'),
preserve_default=True,
),
migrations.AddField(
- model_name='custompkfood',
+ model_name='directcustompkfood',
name='tags',
field=taggit.managers.TaggableManager(to='taggit.Tag', through='tests.TaggedCustomPKFood', help_text='A comma-separated list of tags.', verbose_name='Tags'),
preserve_default=True,
diff --git a/tests/models.py b/tests/models.py
index f20cc38..db1d96c 100644
--- a/tests/models.py
+++ b/tests/models.py
@@ -4,8 +4,8 @@ from django.db import models
from django.utils.encoding import python_2_unicode_compatible
from taggit.managers import TaggableManager
-from taggit.models import (GenericTaggedItemBase, Tag, TagBase, TaggedItem,
- TaggedItemBase)
+from taggit.models import (CommonGenericTaggedItemBase, GenericTaggedItemBase,
+ Tag, TagBase, TaggedItem, TaggedItemBase)
# Ensure that two TaggableManagers with custom through model are allowed.
@@ -90,13 +90,13 @@ class DirectHousePet(DirectPet):
# Test custom through model to model with custom PK
class TaggedCustomPKFood(TaggedItemBase):
- content_object = models.ForeignKey('CustomPKFood')
+ content_object = models.ForeignKey('DirectCustomPKFood')
class TaggedCustomPKPet(TaggedItemBase):
- content_object = models.ForeignKey('CustomPKPet')
+ content_object = models.ForeignKey('DirectCustomPKPet')
@python_2_unicode_compatible
-class CustomPKFood(models.Model):
+class DirectCustomPKFood(models.Model):
name = models.CharField(max_length=50, primary_key=True)
tags = TaggableManager(through=TaggedCustomPKFood)
@@ -105,7 +105,7 @@ class CustomPKFood(models.Model):
return self.name
@python_2_unicode_compatible
-class CustomPKPet(models.Model):
+class DirectCustomPKPet(models.Model):
name = models.CharField(max_length=50, primary_key=True)
tags = TaggableManager(through=TaggedCustomPKPet)
@@ -113,6 +113,32 @@ class CustomPKPet(models.Model):
def __str__(self):
return self.name
+class DirectCustomPKHousePet(DirectCustomPKPet):
+ trained = models.BooleanField(default=False)
+
+# Test custom through model to model with custom PK using GenericForeignKey
+
+class TaggedCustomPK(CommonGenericTaggedItemBase, TaggedItemBase):
+ object_id = models.CharField(max_length=50, verbose_name='Object id', db_index=True)
+
+ at python_2_unicode_compatible
+class CustomPKFood(models.Model):
+ name = models.CharField(max_length=50, primary_key=True)
+
+ tags = TaggableManager(through=TaggedCustomPK)
+
+ def __str__(self):
+ return self.name
+
+ at python_2_unicode_compatible
+class CustomPKPet(models.Model):
+ name = models.CharField(max_length=50, primary_key=True)
+
+ tags = TaggableManager(through=TaggedCustomPK)
+
+ def __str__(self):
+ return self.name
+
class CustomPKHousePet(CustomPKPet):
trained = models.BooleanField(default=False)
diff --git a/tests/tests.py b/tests/tests.py
index 0930dd5..9618c0d 100644
--- a/tests/tests.py
+++ b/tests/tests.py
@@ -11,14 +11,16 @@ from django.test import TestCase, TransactionTestCase
from django.test.utils import override_settings
from django.utils.encoding import force_text
-from .forms import CustomPKFoodForm, DirectFoodForm, FoodForm, OfficialFoodForm
+from .forms import (CustomPKFoodForm, DirectCustomPKFoodForm, DirectFoodForm,
+ FoodForm, OfficialFoodForm)
from .models import (Article, Child, CustomManager, CustomPKFood,
- CustomPKHousePet, CustomPKPet, DirectFood,
+ CustomPKHousePet, CustomPKPet, DirectCustomPKFood,
+ DirectCustomPKHousePet, DirectCustomPKPet, DirectFood,
DirectHousePet, DirectPet, Food, HousePet, Movie,
OfficialFood, OfficialHousePet, OfficialPet,
OfficialTag, OfficialThroughModel, Pet, Photo,
- TaggedCustomPKFood, TaggedCustomPKPet, TaggedFood,
- TaggedPet)
+ TaggedCustomPK, TaggedCustomPKFood, TaggedCustomPKPet,
+ TaggedFood, TaggedPet)
from taggit.managers import _model_name, _TaggableManager, TaggableManager
from taggit.models import Tag, TaggedItem
@@ -102,6 +104,10 @@ class TagModelDirectTestCase(TagModelTestCase):
food_model = DirectFood
tag_model = Tag
+class TagModelDirectCustomPKTestCase(TagModelTestCase):
+ food_model = DirectCustomPKFood
+ tag_model = Tag
+
class TagModelCustomPKTestCase(TagModelTestCase):
food_model = CustomPKFood
tag_model = Tag
@@ -404,11 +410,22 @@ class TaggableManagerDirectTestCase(TaggableManagerTestCase):
housepet_model = DirectHousePet
taggeditem_model = TaggedFood
+class TaggableManagerDirectCustomPKTestCase(TaggableManagerTestCase):
+ food_model = DirectCustomPKFood
+ pet_model = DirectCustomPKPet
+ housepet_model = DirectCustomPKHousePet
+ taggeditem_model = TaggedCustomPKFood
+
+ def test_require_pk(self):
+ # TODO with a charfield pk, pk is never None, so taggit has no way to
+ # tell if the instance is saved or not
+ pass
+
class TaggableManagerCustomPKTestCase(TaggableManagerTestCase):
food_model = CustomPKFood
pet_model = CustomPKPet
housepet_model = CustomPKHousePet
- taggeditem_model = TaggedCustomPKFood
+ taggeditem_model = TaggedCustomPK
def test_require_pk(self):
# TODO with a charfield pk, pk is never None, so taggit has no way to
@@ -507,6 +524,10 @@ class TaggableFormDirectTestCase(TaggableFormTestCase):
form_class = DirectFoodForm
food_model = DirectFood
+class TaggableFormDirectCustomPKTestCase(TaggableFormTestCase):
+ form_class = DirectCustomPKFoodForm
+ food_model = DirectCustomPKFood
+
class TaggableFormCustomPKTestCase(TaggableFormTestCase):
form_class = CustomPKFoodForm
food_model = CustomPKFood
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/collab-maint/django-taggit.git
More information about the Python-modules-commits
mailing list