diff -Nru django-taggit-0.21.3/AUTHORS django-taggit-0.22.1/AUTHORS --- django-taggit-0.21.3/AUTHORS 2016-05-23 14:18:35.000000000 +0000 +++ django-taggit-0.22.1/AUTHORS 2017-01-24 03:28:48.000000000 +0000 @@ -14,3 +14,4 @@ Charles Leifer Florian Apolloner Andrew Pryde +John Whitlock diff -Nru django-taggit-0.21.3/CHANGELOG.txt django-taggit-0.22.1/CHANGELOG.txt --- django-taggit-0.21.3/CHANGELOG.txt 2016-10-08 03:22:31.000000000 +0000 +++ django-taggit-0.22.1/CHANGELOG.txt 2017-04-23 01:57:37.000000000 +0000 @@ -1,6 +1,41 @@ Changelog ========= +0.22.1 (2017-04-22) +~~~~~~~~~~~~~~~~~~~ + * Update spanish translation + * https://github.com/alex/django-taggit/pull/473 + * Add testing for Django 1.11 and Python 3.6 + * https://github.com/alex/django-taggit/pull/475 + * introduce isort and flake8 in the CI + * https://github.com/alex/django-taggit/pull/476 + * [docs] Fixed links to external apps + * https://github.com/alex/django-taggit/pull/481 + * Improved auto-slug in TagBase to support UUID pk + * https://github.com/alex/django-taggit/pull/482 + * [docs] Added contribution guidelines + * https://github.com/alex/django-taggit/pull/480 + +0.22.0 (2017-01-29) +~~~~~~~~~~~~~~~~~~~ + * **Backwards incompatible:** Drop support for Django 1.7 + * https://github.com/alex/django-taggit/pull/465 + +0.21.6 (2017-01-25) +~~~~~~~~~~~~~~~~~~~ + * Fix case-insensitive tag creation when setting to a mix of new and existing tags are used + * https://github.com/alex/django-taggit/pull/464 + +0.21.5 (2017-01-21) +~~~~~~~~~~~~~~~~~~~ + * Check for case-insensitive duplicates when creating new tags + * https://github.com/alex/django-taggit/pull/461 + +0.21.4 (2017-01-10) +~~~~~~~~~~~~~~~~~~~ + * Support __gt__ and __lt__ ordering on Tags + * https://github.com/alex/django-taggit/pull/456 + 0.21.3 (2016-10-07) ~~~~~~~~~~~~~~~~~~~ * Fix list view diff -Nru django-taggit-0.21.3/debian/changelog django-taggit-0.22.1/debian/changelog --- django-taggit-0.21.3/debian/changelog 2016-11-17 10:20:57.000000000 +0000 +++ django-taggit-0.22.1/debian/changelog 2017-07-10 17:57:28.000000000 +0000 @@ -1,3 +1,10 @@ +django-taggit (0.22.1-1) unstable; urgency=medium + + * New upstream release. + * Bump standards to 4.0.0. + + -- Michal Čihař Mon, 10 Jul 2017 19:57:28 +0200 + django-taggit (0.21.3-1) unstable; urgency=medium * New upstream release. diff -Nru django-taggit-0.21.3/debian/control django-taggit-0.22.1/debian/control --- django-taggit-0.21.3/debian/control 2016-11-16 12:33:23.000000000 +0000 +++ django-taggit-0.22.1/debian/control 2017-07-10 17:57:23.000000000 +0000 @@ -18,7 +18,7 @@ python-django (= 1:1.10-2), python3-django (= 1:1.10-1), python3-django (= 1:1.10-2) -Standards-Version: 3.9.8 +Standards-Version: 4.0.0 Vcs-Browser: https://anonscm.debian.org/git/python-modules/packages/django-taggit.git Vcs-Git: https://anonscm.debian.org/git/python-modules/packages/django-taggit.git Homepage: https://github.com/alex/django-taggit diff -Nru django-taggit-0.21.3/debian/patches/0001-Add-missing-TEMPLATES-settings-to-runtests.py.patch django-taggit-0.22.1/debian/patches/0001-Add-missing-TEMPLATES-settings-to-runtests.py.patch --- django-taggit-0.21.3/debian/patches/0001-Add-missing-TEMPLATES-settings-to-runtests.py.patch 2016-11-17 10:20:57.000000000 +0000 +++ django-taggit-0.22.1/debian/patches/0001-Add-missing-TEMPLATES-settings-to-runtests.py.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -From f17b969bfa18ba0335f95352ff301926e0b98535 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= -Date: Thu, 17 Nov 2016 11:32:33 +0100 -Subject: [PATCH 1/1] Add missing TEMPLATES settings to runtests.py - ---- - runtests.py | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/runtests.py b/runtests.py -index 36a7d4e..731b177 100755 ---- a/runtests.py -+++ b/runtests.py -@@ -18,6 +18,12 @@ if not settings.configured: - 'tests', - ], - MIDDLEWARE_CLASSES=[], -+ TEMPLATES = [ -+ { -+ 'BACKEND': 'django.template.backends.django.DjangoTemplates', -+ 'APP_DIRS': True, -+ } -+ ], - ) - - --- -2.10.2 - diff -Nru django-taggit-0.21.3/debian/patches/series django-taggit-0.22.1/debian/patches/series --- django-taggit-0.21.3/debian/patches/series 2016-11-17 10:20:57.000000000 +0000 +++ django-taggit-0.22.1/debian/patches/series 2017-07-10 17:57:28.000000000 +0000 @@ -1,2 +1 @@ -0001-Add-missing-TEMPLATES-settings-to-runtests.py.patch remove-isort.patch diff -Nru django-taggit-0.21.3/django_taggit.egg-info/PKG-INFO django-taggit-0.22.1/django_taggit.egg-info/PKG-INFO --- django-taggit-0.21.3/django_taggit.egg-info/PKG-INFO 2016-10-08 03:24:02.000000000 +0000 +++ django-taggit-0.22.1/django_taggit.egg-info/PKG-INFO 2017-04-23 02:01:59.000000000 +0000 @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: django-taggit -Version: 0.21.3 +Version: 0.22.1 Summary: django-taggit is a reusable Django application for simple tagging. Home-page: http://github.com/alex/django-taggit/tree/master Author: Alex Gaynor @@ -44,7 +44,7 @@ Tags will show up for you automatically in forms and the admin. - ``django-taggit`` requires Django 1.7 or greater. + ``django-taggit`` requires Django 1.8 or greater. For more info check out the `documentation `_. And for questions about usage or development you can contact the @@ -54,10 +54,10 @@ Classifier: Development Status :: 5 - Production/Stable Classifier: Environment :: Web Environment Classifier: Framework :: Django -Classifier: Framework :: Django :: 1.7 Classifier: Framework :: Django :: 1.8 Classifier: Framework :: Django :: 1.9 Classifier: Framework :: Django :: 1.10 +Classifier: Framework :: Django :: 1.11 Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: BSD License Classifier: Operating System :: OS Independent @@ -66,3 +66,4 @@ Classifier: Programming Language :: Python :: 3.3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 diff -Nru django-taggit-0.21.3/django_taggit.egg-info/SOURCES.txt django-taggit-0.22.1/django_taggit.egg-info/SOURCES.txt --- django-taggit-0.21.3/django_taggit.egg-info/SOURCES.txt 2016-10-08 03:24:02.000000000 +0000 +++ django-taggit-0.22.1/django_taggit.egg-info/SOURCES.txt 2017-04-23 02:01:59.000000000 +0000 @@ -17,6 +17,7 @@ docs/api.txt docs/changelog.txt docs/conf.py +docs/contributing.txt docs/custom_tagging.txt docs/external_apps.txt docs/forms.txt @@ -70,5 +71,6 @@ tests/tests.py tests/urls.py tests/migrations/0001_initial.py +tests/migrations/0002_uuid_models.py tests/migrations/__init__.py tests/templates/tests/food_tag_list.html \ No newline at end of file diff -Nru django-taggit-0.21.3/docs/contributing.txt django-taggit-0.22.1/docs/contributing.txt --- django-taggit-0.21.3/docs/contributing.txt 1970-01-01 00:00:00.000000000 +0000 +++ django-taggit-0.22.1/docs/contributing.txt 2017-04-23 01:58:35.000000000 +0000 @@ -0,0 +1,95 @@ +Contributing to taggit +====================== + +Thank you for taking the time to contribute to django-taggit. + +Follow these guidelines to speed up the process. + +.. contents:: **Table of Contents**: + :backlinks: none + :depth: 3 + +Reach out before you start +-------------------------- + +Before opening a new issue, try the following steps: + +- look if somebody else has already started working on the same issue + by looking in the `github issues `_ + and `pull requests `_ +- look also in the `django-taggit mailinglist `_ +- announce your intentions by opening a new issue +- present yourself on the mailing list + +Fork repo and install your fork +------------------------------- + +Once you have forked this repository to your own github account or organization, +install your own fork in your development environment: + +.. code-block:: shell + + git clone git@github.com:/django-taggit.git + cd django-taggit + python setup.py develop + +Running tests +------------- + +.. code-block:: shell + + make test + +Opening the django shell +------------------------ + +.. code-block:: shell + + ./manage.py shell + +Creating new migrations +--------------------- + +.. code-block:: shell + + ./manage.py makemigrations + + +Follow style conventions (PEP8, isort) +-------------------------------------- + +Check that your changes are not breaking the style conventions with: + +.. code-block:: shell + + flake8 taggit + python setup.py isort + +For more information, please see: + +- `PEP8: Style Guide for Python Code `_ +- `isort: a python utility / library to sort imports `_ + +Update documentation +-------------------- + +If you introduce new features or change existing documented behavior, +please remember to update the documentation! + +The documentation is located in the ``/docs`` directory +of the repository. + +To do work on the docs, proceed with the following steps: + +.. code-block:: shell + + cd docs/ + pip install sphinx + # update the text files with your favorite text editor + make html + +Send pull request +----------------- + +Now is time to push your changes to github and open a +`pull request `_! diff -Nru django-taggit-0.21.3/docs/external_apps.txt django-taggit-0.22.1/docs/external_apps.txt --- django-taggit-0.21.3/docs/external_apps.txt 2016-08-23 01:08:09.000000000 +0000 +++ django-taggit-0.22.1/docs/external_apps.txt 2017-04-23 01:58:35.000000000 +0000 @@ -10,29 +10,24 @@ Despite their mention here, the following applications are in no way official, nor have they in any way been reviewed or tested. - If you have an application that you'd like to see listed here, simply fork -``taggit`` on `github`__, add it to this list, and send a pull request. - +`django-taggit on github `_, +add it to this list, and send a pull request. - * ``django-taggit-helpers``: Makes it easier to work with admin pages of models + * `django-taggit-helpers `_: + Makes it easier to work with admin pages of models associated with ``taggit`` tags by adding helper classes: ``TaggitCounter``, ``TaggitListFilter``, ``TaggitStackedInline``, ``TaggitTabularInline``. - Available on `github`__. - * ``django-taggit-labels``: Provides a clickable label widget for the + * `django-taggit-labels `_: + Provides a clickable label widget for the Django admin for user friendly selection from managed tag sets. - * ``django-taggit-serializer``: Adds functionality for using ``taggit`` with - ``django-rest-framework``. Available on `github`__. - * ``django-taggit-suggest``: Provides support for defining keyword and regular + * `django-taggit-serializer `_: + Adds functionality for using ``taggit`` with + ``django-rest-framework``. + * `django-taggit-suggest `_: + Provides support for defining keyword and regular expression rules for suggesting new tags for content. This used to be - available at ``taggit.contrib.suggest``. Available on `github`__. - * ``django-taggit-templatetags``: Provides several templatetags, including one + available at ``taggit.contrib.suggest``. + * `django-taggit-templatetags `_: + Provides several templatetags, including one for tag clouds, to expose various ``taggit`` APIs directly to templates. - Available on `github`__. - -__ https://github.com/alex/django-taggit -__ https://github.com/mfcovington/django-taggit-helpers -__ https://github.com/bennylope/django-taggit-labels -__ https://github.com/glemmaPaul/django-taggit-serializer -__ https://github.com/frankwiles/django-taggit-suggest -__ https://github.com/feuervogel/django-taggit-templatetags diff -Nru django-taggit-0.21.3/docs/index.txt django-taggit-0.22.1/docs/index.txt --- django-taggit-0.21.3/docs/index.txt 2016-08-26 06:20:33.000000000 +0000 +++ django-taggit-0.22.1/docs/index.txt 2017-04-23 01:58:35.000000000 +0000 @@ -4,7 +4,7 @@ ``django-taggit`` is a reusable Django application designed to making adding tagging to your project easy and fun. -``django-taggit`` works with Django 1.7+ and Python 2.7-3.X. +``django-taggit`` works with Django 1.8+ and Python 2.7-3.X. .. toctree:: :maxdepth: 2 @@ -14,6 +14,7 @@ admin api custom_tagging + contributing external_apps changelog diff -Nru django-taggit-0.21.3/PKG-INFO django-taggit-0.22.1/PKG-INFO --- django-taggit-0.21.3/PKG-INFO 2016-10-08 03:24:02.000000000 +0000 +++ django-taggit-0.22.1/PKG-INFO 2017-04-23 02:01:59.000000000 +0000 @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: django-taggit -Version: 0.21.3 +Version: 0.22.1 Summary: django-taggit is a reusable Django application for simple tagging. Home-page: http://github.com/alex/django-taggit/tree/master Author: Alex Gaynor @@ -44,7 +44,7 @@ Tags will show up for you automatically in forms and the admin. - ``django-taggit`` requires Django 1.7 or greater. + ``django-taggit`` requires Django 1.8 or greater. For more info check out the `documentation `_. And for questions about usage or development you can contact the @@ -54,10 +54,10 @@ Classifier: Development Status :: 5 - Production/Stable Classifier: Environment :: Web Environment Classifier: Framework :: Django -Classifier: Framework :: Django :: 1.7 Classifier: Framework :: Django :: 1.8 Classifier: Framework :: Django :: 1.9 Classifier: Framework :: Django :: 1.10 +Classifier: Framework :: Django :: 1.11 Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: BSD License Classifier: Operating System :: OS Independent @@ -66,3 +66,4 @@ Classifier: Programming Language :: Python :: 3.3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 diff -Nru django-taggit-0.21.3/README.rst django-taggit-0.22.1/README.rst --- django-taggit-0.21.3/README.rst 2016-08-23 01:08:09.000000000 +0000 +++ django-taggit-0.22.1/README.rst 2017-04-23 01:46:16.000000000 +0000 @@ -36,7 +36,7 @@ Tags will show up for you automatically in forms and the admin. -``django-taggit`` requires Django 1.7 or greater. +``django-taggit`` requires Django 1.8 or greater. For more info check out the `documentation `_. And for questions about usage or development you can contact the diff -Nru django-taggit-0.21.3/runtests.py django-taggit-0.22.1/runtests.py --- django-taggit-0.21.3/runtests.py 2016-05-23 14:18:35.000000000 +0000 +++ django-taggit-0.22.1/runtests.py 2017-04-23 01:58:35.000000000 +0000 @@ -18,6 +18,12 @@ 'tests', ], MIDDLEWARE_CLASSES=[], + TEMPLATES=[ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'APP_DIRS': True, + } + ], ) diff -Nru django-taggit-0.21.3/setup.cfg django-taggit-0.22.1/setup.cfg --- django-taggit-0.21.3/setup.cfg 2016-10-08 03:24:02.000000000 +0000 +++ django-taggit-0.22.1/setup.cfg 2017-04-23 02:01:59.000000000 +0000 @@ -5,8 +5,9 @@ universal = 1 [flake8] +max-line-length = 119 ignore = E501,E302 -exclude = migrations +exclude = migrations,docs [isort] forced_separate = tests,taggit @@ -15,5 +16,4 @@ [egg_info] tag_build = tag_date = 0 -tag_svn_revision = 0 diff -Nru django-taggit-0.21.3/setup.py django-taggit-0.22.1/setup.py --- django-taggit-0.21.3/setup.py 2016-08-31 22:30:32.000000000 +0000 +++ django-taggit-0.22.1/setup.py 2017-04-23 01:58:35.000000000 +0000 @@ -2,7 +2,6 @@ import taggit - with open('README.rst') as f: readme = f.read() @@ -15,7 +14,7 @@ author_email='alex.gaynor@gmail.com', url='http://github.com/alex/django-taggit/tree/master', packages=find_packages(exclude=('tests*',)), - package_data = { + package_data={ 'taggit': [ 'locale/*/LC_MESSAGES/*', ], @@ -25,10 +24,10 @@ 'Development Status :: 5 - Production/Stable', 'Environment :: Web Environment', 'Framework :: Django', - 'Framework :: Django :: 1.7', 'Framework :: Django :: 1.8', 'Framework :: Django :: 1.9', 'Framework :: Django :: 1.10', + 'Framework :: Django :: 1.11', 'Intended Audience :: Developers', 'License :: OSI Approved :: BSD License', 'Operating System :: OS Independent', @@ -37,6 +36,7 @@ 'Programming Language :: Python :: 3.3', 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', ], include_package_data=True, zip_safe=False, diff -Nru django-taggit-0.21.3/taggit/__init__.py django-taggit-0.22.1/taggit/__init__.py --- django-taggit-0.21.3/taggit/__init__.py 2016-10-08 03:23:30.000000000 +0000 +++ django-taggit-0.22.1/taggit/__init__.py 2017-04-23 02:01:36.000000000 +0000 @@ -1,3 +1,3 @@ -VERSION = (0, 21, 3) +VERSION = (0, 22, 1) default_app_config = 'taggit.apps.TaggitAppConfig' diff -Nru django-taggit-0.21.3/taggit/locale/es/LC_MESSAGES/django.po django-taggit-0.22.1/taggit/locale/es/LC_MESSAGES/django.po --- django-taggit-0.21.3/taggit/locale/es/LC_MESSAGES/django.po 2016-05-23 14:18:35.000000000 +0000 +++ django-taggit-0.22.1/taggit/locale/es/LC_MESSAGES/django.po 2017-04-23 01:58:35.000000000 +0000 @@ -20,7 +20,7 @@ #: forms.py:27 msgid "Please provide a comma-separated list of tags." -msgstr "Por favor provea una lista de etiquetas separadas por coma." +msgstr "Por favor introduzca una lista de etiquetas separadas por coma." #: managers.py:297 models.py:101 msgid "Tags" @@ -36,7 +36,7 @@ #: models.py:47 msgid "Slug" -msgstr "Marquilla" +msgstr "Slug" #: models.py:100 msgid "Tag" diff -Nru django-taggit-0.21.3/taggit/managers.py django-taggit-0.22.1/taggit/managers.py --- django-taggit-0.21.3/taggit/managers.py 2016-08-26 06:20:33.000000000 +0000 +++ django-taggit-0.22.1/taggit/managers.py 2017-04-23 01:46:16.000000000 +0000 @@ -12,36 +12,21 @@ from django.db.models.fields import Field from django.db.models.fields.related import (ManyToManyRel, OneToOneRel, RelatedField) +from django.db.models.query_utils import PathInfo from django.utils import six from django.utils.text import capfirst from django.utils.translation import ugettext_lazy as _ from taggit.forms import TagField from taggit.models import CommonGenericTaggedItemBase, TaggedItem -from taggit.utils import (_get_field, _related_model, _remote_field, +from taggit.utils import (_related_model, _remote_field, require_instance_manager) -if VERSION < (1, 8): - # related.py was removed in Django 1.8 - - # Depending on how Django was updated, related.py could still exist - # on the users system even on Django 1.8+, so we check the Django - # version before importing it to make sure this doesn't get imported - # accidentally. - from django.db.models.related import RelatedObject -else: - RelatedObject = None - - if VERSION >= (1, 9): from django.db.models.fields.related import lazy_related_operation else: from django.db.models.fields.related import add_lazy_relation -try: - from django.db.models.query_utils import PathInfo -except ImportError: # Django < 1.8 - from django.db.models.related import PathInfo class TaggableRel(ManyToManyRel): def __init__(self, field, related_name, through, to=None): @@ -76,11 +61,8 @@ self.col = col self.content_types = content_types - def as_sql(self, qn, connection): - # qn changed from a quoting function to be a compiler object in 1.8, - # which has a quote function - if VERSION >= (1, 8): - qn = qn.quote_name_unless_alias + def as_sql(self, compiler, connection): + qn = compiler.quote_name_unless_alias if len(self.content_types) == 1: extra_where = "%s.%s = %%s" % (qn(self.alias), qn(self.col)) else: @@ -197,7 +179,10 @@ "Cannot add {0} ({1}). Expected {2} or str.".format( t, type(t), type(self.through.tag_model()))) - if getattr(settings, 'TAGGIT_CASE_INSENSITIVE', False): + case_insensitive = getattr(settings, 'TAGGIT_CASE_INSENSITIVE', False) + manager = self.through.tag_model()._default_manager.using(db) + + if case_insensitive: # Some databases can do case-insensitive comparison with IN, which # would be faster, but we can't rely on it or easily detect it. existing = [] @@ -205,28 +190,28 @@ for name in str_tags: try: - tag = (self.through.tag_model()._default_manager - .using(db) - .get(name__iexact=name)) + tag = manager.get(name__iexact=name) existing.append(tag) except self.through.tag_model().DoesNotExist: tags_to_create.append(name) else: # If str_tags has 0 elements Django actually optimizes that to not # do a query. Malcolm is very smart. - existing = (self.through.tag_model()._default_manager - .using(db) - .filter(name__in=str_tags)) - + existing = manager.filter(name__in=str_tags) tags_to_create = str_tags - set(t.name for t in existing) tag_objs.update(existing) for new_tag in tags_to_create: - tag_objs.add( - self.through.tag_model()._default_manager - .using(db) - .create(name=new_tag)) + if case_insensitive: + try: + tag = manager.get(name__iexact=new_tag) + except self.through.tag_model().DoesNotExist: + tag = manager.create(name=new_tag) + else: + tag = manager.create(name=new_tag) + + tag_objs.add(tag) return tag_objs @@ -340,7 +325,7 @@ if len(lookup_keys) == 1: # Can we do this without a second query by using a select_related() # somehow? - f = _get_field(self.through, lookup_keys[0]) + f = self.through._meta.get_field(lookup_keys[0]) remote_field = _remote_field(f) rel_model = _related_model(_remote_field(f)) objs = rel_model._default_manager.filter(**{ @@ -496,9 +481,6 @@ return False def post_through_setup(self, cls): - if RelatedObject is not None: # Django < 1.8 - self.related = RelatedObject(cls, self.model, self) - self.use_gfk = ( self.through is None or issubclass(self.through, CommonGenericTaggedItemBase) ) @@ -511,9 +493,6 @@ if not self.rel.to: self.rel.to = self.through._meta.get_field("tag").rel.to - if RelatedObject is not None: # Django < 1.8 - self.related = RelatedObject(self.through, cls, self) - if self.use_gfk: tagged_items = GenericRelation(self.through) tagged_items.contribute_to_class(cls, 'tagged_items') @@ -546,10 +525,10 @@ return self.model._meta.model_name def m2m_reverse_name(self): - return _get_field(self.through, 'tag').column + return self.through._meta.get_field('tag').column def m2m_reverse_field_name(self): - return _get_field(self.through, 'tag').name + return self.through._meta.get_field('tag').name def m2m_target_field_name(self): return self.model._meta.pk.name @@ -591,7 +570,7 @@ alias_to_join = rhs_alias else: alias_to_join = lhs_alias - extra_col = _get_field(self.through, 'content_type').column + extra_col = self.through._meta.get_field('content_type').column content_type_ids = [ContentType.objects.get_for_model(subclass).pk for subclass in _get_subclasses(self.model)] if len(content_type_ids) == 1: @@ -609,8 +588,8 @@ def _get_mm_case_path_info(self, direct=False): pathinfos = [] - linkfield1 = _get_field(self.through, 'content_object') - linkfield2 = _get_field(self.through, self.m2m_reverse_field_name()) + linkfield1 = self.through._meta.get_field('content_object') + linkfield2 = self.through._meta.get_field(self.m2m_reverse_field_name()) if direct: join1infos = linkfield1.get_reverse_path_info() join2infos = linkfield2.get_path_info() @@ -625,7 +604,7 @@ pathinfos = [] from_field = self.model._meta.pk opts = self.through._meta - linkfield = _get_field(self.through, self.m2m_reverse_field_name()) + linkfield = self.through._meta.get_field(self.m2m_reverse_field_name()) if direct: join1infos = [PathInfo(self.model._meta, opts, [from_field], _remote_field(self), True, False)] join2infos = linkfield.get_path_info() @@ -655,7 +634,7 @@ return (("object_id", self.model._meta.pk.column),) def get_extra_restriction(self, where_class, alias, related_alias): - extra_col = _get_field(self.through, 'content_type').column + extra_col = self.through._meta.get_field('content_type').column content_type_ids = [ContentType.objects.get_for_model(subclass).pk for subclass in _get_subclasses(self.model)] return ExtraJoinRestriction(related_alias, extra_col, content_type_ids) @@ -665,7 +644,7 @@ @property def related_fields(self): - return [(_get_field(self.through, 'object_id'), self.model._meta.pk)] + return [(self.through._meta.get_field('object_id'), self.model._meta.pk)] @property def foreign_related_fields(self): @@ -674,20 +653,9 @@ def _get_subclasses(model): subclasses = [model] - if VERSION < (1, 8): - all_fields = (_get_field(model, f) for f in model._meta.get_all_field_names()) - else: - all_fields = model._meta.get_fields() - for field in all_fields: - # Django 1.8 + - if (not RelatedObject and isinstance(field, OneToOneRel) and - getattr(_remote_field(field.field), "parent_link", None)): + for field in model._meta.get_fields(): + if isinstance(field, OneToOneRel) and getattr(_remote_field(field.field), "parent_link", None): subclasses.extend(_get_subclasses(field.related_model)) - - # < Django 1.8 - if (RelatedObject and isinstance(field, RelatedObject) and - getattr(field.field.rel, "parent_link", None)): - subclasses.extend(_get_subclasses(field.model)) return subclasses diff -Nru django-taggit-0.21.3/taggit/models.py django-taggit-0.22.1/taggit/models.py --- django-taggit-0.21.3/taggit/models.py 2016-08-26 06:20:33.000000000 +0000 +++ django-taggit-0.22.1/taggit/models.py 2017-04-23 01:58:35.000000000 +0000 @@ -10,8 +10,6 @@ from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext -from taggit.utils import _get_field - try: from unidecode import unidecode except ImportError: @@ -27,11 +25,17 @@ def __str__(self): return self.name + def __gt__(self, other): + return self.name.lower() > other.name.lower() + + def __lt__(self, other): + return self.name.lower() < other.name.lower() + class Meta: abstract = True def save(self, *args, **kwargs): - if not self.pk and not self.slug: + if self._state.adding and not self.slug: self.slug = self.slugify(self.name) from django.db import router using = kwargs.get("using") or router.db_for_write( @@ -93,12 +97,12 @@ @classmethod def tag_model(cls): - field = _get_field(cls, 'tag') + field = cls._meta.get_field('tag') return field.remote_field.model if VERSION >= (1, 9) else field.rel.to @classmethod def tag_relname(cls): - field = _get_field(cls, 'tag') + field = cls._meta.get_field('tag') return field.remote_field.related_name if VERSION >= (1, 9) else field.rel.related_name @classmethod @@ -188,13 +192,11 @@ abstract = True -if VERSION >= (1, 8): +class GenericUUIDTaggedItemBase(CommonGenericTaggedItemBase): + object_id = models.UUIDField(verbose_name=_('Object id'), db_index=True) - class GenericUUIDTaggedItemBase(CommonGenericTaggedItemBase): - object_id = models.UUIDField(verbose_name=_('Object id'), db_index=True) - - class Meta: - abstract = True + class Meta: + abstract = True class TaggedItem(GenericTaggedItemBase, TaggedItemBase): diff -Nru django-taggit-0.21.3/taggit/utils.py django-taggit-0.22.1/taggit/utils.py --- django-taggit-0.21.3/taggit/utils.py 2016-03-30 04:07:40.000000000 +0000 +++ django-taggit-0.22.1/taggit/utils.py 2017-04-23 01:46:16.000000000 +0000 @@ -9,13 +9,6 @@ from django.utils.functional import wraps -def _get_field(model, name): - if VERSION < (1, 8): - return model._meta.get_field_by_name(name)[0] - else: - return model._meta.get_field(name) - - def _remote_field(field): if VERSION < (1, 9): return field.rel @@ -164,6 +157,7 @@ get_func.cache[func_path] = func return func + # Create a cache as an attribute on the function that way it can cache the # imported callable rather than re-importing it each time `parse_tags` or # `edit_string_for_tags` needs the callable. diff -Nru django-taggit-0.21.3/tests/forms.py django-taggit-0.22.1/tests/forms.py --- django-taggit-0.21.3/tests/forms.py 2016-08-26 06:20:33.000000000 +0000 +++ django-taggit-0.22.1/tests/forms.py 2017-04-23 01:58:35.000000000 +0000 @@ -1,6 +1,6 @@ from __future__ import absolute_import, unicode_literals -from django import VERSION, forms +from django import forms from .models import (CustomPKFood, DirectCustomPKFood, DirectFood, Food, OfficialFood) diff -Nru django-taggit-0.21.3/tests/migrations/0002_uuid_models.py django-taggit-0.22.1/tests/migrations/0002_uuid_models.py --- django-taggit-0.21.3/tests/migrations/0002_uuid_models.py 1970-01-01 00:00:00.000000000 +0000 +++ django-taggit-0.22.1/tests/migrations/0002_uuid_models.py 2017-04-23 01:58:35.000000000 +0000 @@ -0,0 +1,54 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.7 on 2017-04-19 11:21 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion +import taggit.managers +import uuid + + +class Migration(migrations.Migration): + + dependencies = [ + ('contenttypes', '0002_remove_content_type_name'), + ('tests', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='UUIDFood', + fields=[ + ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), + ('name', models.CharField(max_length=50)), + ], + ), + migrations.CreateModel( + name='UUIDTag', + fields=[ + ('name', models.CharField(max_length=100, unique=True, verbose_name='Name')), + ('slug', models.SlugField(max_length=100, unique=True, verbose_name='Slug')), + ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), + ], + options={ + 'abstract': False, + }, + ), + migrations.CreateModel( + name='UUIDTaggedItem', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('object_id', models.UUIDField(db_index=True, verbose_name='Object id')), + ('content_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='tests_uuidtaggeditem_tagged_items', to='contenttypes.ContentType', verbose_name='Content type')), + ('tag', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='tests_uuidtaggeditem_items', to='tests.UUIDTag')), + ], + options={ + 'abstract': False, + }, + ), + migrations.AddField( + model_name='uuidfood', + name='tags', + field=taggit.managers.TaggableManager(help_text='A comma-separated list of tags.', through='tests.UUIDTaggedItem', to='tests.UUIDTag', verbose_name='Tags'), + ), + ] diff -Nru django-taggit-0.21.3/tests/models.py django-taggit-0.22.1/tests/models.py --- django-taggit-0.21.3/tests/models.py 2016-05-23 14:18:35.000000000 +0000 +++ django-taggit-0.22.1/tests/models.py 2017-04-23 01:58:35.000000000 +0000 @@ -1,11 +1,14 @@ from __future__ import unicode_literals +import uuid + from django.db import models from django.utils.encoding import python_2_unicode_compatible from taggit.managers import TaggableManager from taggit.models import (CommonGenericTaggedItemBase, GenericTaggedItemBase, - Tag, TagBase, TaggedItem, TaggedItemBase) + GenericUUIDTaggedItemBase, Tag, TagBase, TaggedItem, + TaggedItemBase) # Ensure that two TaggableManagers with custom through model are allowed. @@ -103,7 +106,6 @@ @python_2_unicode_compatible class DirectCustomPKFood(models.Model): name = models.CharField(max_length=50, primary_key=True) - tags = TaggableManager(through=TaggedCustomPKFood) def __str__(self): @@ -243,3 +245,23 @@ class Child(Parent): pass + + +@python_2_unicode_compatible +class UUIDFood(models.Model): + id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) + name = models.CharField(max_length=50) + tags = TaggableManager(through='UUIDTaggedItem') + + def __str__(self): + return self.name + + +class UUIDTag(TagBase): + id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) + + +class UUIDTaggedItem(GenericUUIDTaggedItemBase): + tag = models.ForeignKey(UUIDTag, + related_name='%(app_label)s_%(class)s_items', + on_delete=models.CASCADE) diff -Nru django-taggit-0.21.3/tests/tests.py django-taggit-0.22.1/tests/tests.py --- django-taggit-0.21.3/tests/tests.py 2016-10-08 03:21:50.000000000 +0000 +++ django-taggit-0.22.1/tests/tests.py 2017-04-23 01:58:35.000000000 +0000 @@ -3,18 +3,18 @@ import sys import warnings from unittest import TestCase as UnitTestCase -from unittest import skipIf, skipUnless import django import mock from django.contrib.contenttypes.models import ContentType from django.core import serializers -from django.core.exceptions import ImproperlyConfigured, ValidationError +from django.core.exceptions import ValidationError from django.core.management import call_command from django.db import connection, models from django.test import RequestFactory, TestCase, TransactionTestCase from django.test.utils import override_settings from django.utils.encoding import force_text +from django.views.generic.list import ListView from .forms import (CustomPKFoodForm, DirectCustomPKFoodForm, DirectFoodForm, FoodForm, OfficialFoodForm) @@ -24,13 +24,14 @@ DirectHousePet, DirectPet, Food, HousePet, Movie, OfficialFood, OfficialHousePet, OfficialPet, OfficialTag, OfficialThroughModel, Pet, Photo, TaggedCustomPK, - TaggedCustomPKFood, TaggedFood) + TaggedCustomPKFood, TaggedFood, + UUIDFood, UUIDTag) from taggit.managers import TaggableManager, _TaggableManager from taggit.models import Tag, TaggedItem -from taggit.views import tagged_object_list, TagListMixin from taggit.utils import (_related_model, _remote_field, edit_string_for_tags, parse_tags) +from taggit.views import TagListMixin, tagged_object_list class BaseTaggingTest(object): @@ -110,6 +111,18 @@ r"Expected or str.")): apple.tags.add(1) + def test_gt(self): + high = self.tag_model.objects.create(name='high') + low = self.tag_model.objects.create(name='Low') + self.assertTrue(low > high) + self.assertFalse(high > low) + + def test_lt(self): + high = self.tag_model.objects.create(name='high') + low = self.tag_model.objects.create(name='Low') + self.assertTrue(high < low) + self.assertFalse(low < high) + class TagModelDirectTestCase(TagModelTestCase): food_model = DirectFood @@ -598,13 +611,8 @@ self.assertTrue(hasattr(field, 'rel')) self.assertTrue(hasattr(field.rel, 'to')) - # This API has changed in Django 1.8 - # https://code.djangoproject.com/ticket/21414 - if django.VERSION >= (1, 8): - self.assertEqual(self.food_model, field.model) - self.assertEqual(self.tag_model, _remote_field(field).model) - else: - self.assertEqual(self.food_model, field.related.model) + self.assertEqual(self.food_model, field.model) + self.assertEqual(self.tag_model, _remote_field(field).model) def test_names_method(self): apple = self.food_model.objects.create(name="apple") @@ -656,6 +664,23 @@ orange.tags.add('spain') self.assertEqual(list(orange.tags.all()), [spain]) + @override_settings(TAGGIT_CASE_INSENSITIVE=True) + def test_with_case_insensitive_option_and_creation(self): + orange = self.food_model.objects.create(name="orange") + orange.tags.add('spain', 'Spain') + tag_names = list(orange.tags.names()) + self.assertEqual(len(tag_names), 1, tag_names) + + @override_settings(TAGGIT_CASE_INSENSITIVE=True) + def test_with_case_insensitive_option_new_and_old(self): + orange = self.food_model.objects.create(name="orange") + orange.tags.add('Spain') + tag_names = list(orange.tags.names()) + self.assertEqual(len(tag_names), 1, tag_names) + orange.tags.add('spain', 'Valencia') + tag_names = sorted(orange.tags.names()) + self.assertEqual(tag_names, ['Spain', 'Valencia']) + class TaggableManagerDirectTestCase(TaggableManagerTestCase): food_model = DirectFood @@ -961,9 +986,6 @@ call_command('check', tag=['models']) -from django.views.generic.list import ListView - - class FoodTagListView(TagListMixin, ListView): model = Food @@ -998,3 +1020,7 @@ self.assertIn(self.apple, response.context_data['object_list']) self.assertNotIn(self.strawberry, response.context_data['object_list']) + +class TagUUIDModelTestCase(TagModelTestCase): + food_model = UUIDFood + tag_model = UUIDTag diff -Nru django-taggit-0.21.3/tox.ini django-taggit-0.22.1/tox.ini --- django-taggit-0.21.3/tox.ini 2016-08-26 06:20:33.000000000 +0000 +++ django-taggit-0.22.1/tox.ini 2017-04-23 01:58:35.000000000 +0000 @@ -1,16 +1,29 @@ [tox] envlist = - {py27,py33,py34}-1.7.x {py27,py33,py34,py35}-1.8.x {py27,py34,py35}-1.9.x {py27,py34,py35}-1.10.x + {py27,py34,py35,py36}-1.11.x [testenv] deps = - 1.7.x: https://github.com/django/django/archive/stable/1.7.x.tar.gz#egg=django 1.8.x: https://github.com/django/django/archive/stable/1.8.x.tar.gz#egg=django 1.9.x: https://github.com/django/django/archive/stable/1.9.x.tar.gz#egg=django 1.10.x: https://github.com/django/django/archive/stable/1.10.x.tar.gz#egg=django + 1.11.x: https://github.com/django/django/archive/stable/1.11.x.tar.gz#egg=django commands = make develop test whitelist_externals = make + +[testenv:flake8] +skip_install = true +usedevelop = false +changedir = {toxinidir} +deps = flake8 +commands = flake8 *.py taggit/ tests/ + +[testenv:isort] +usedevelop = false +deps = isort +changedir = {toxinidir} +commands = isort --recursive --check-only --diff taggit tests