[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