From 7638a13f6557df9b130896959103cd5650287a12 Mon Sep 17 00:00:00 2001 From: Hugbot Date: Sun, 8 Sep 2019 21:38:50 -0700 Subject: [PATCH 01/30] Change `docs/quickstart.rst` version support to match `README.rst`. --- docs/quickstart.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/quickstart.rst b/docs/quickstart.rst index c40cb06..c659fbd 100644 --- a/docs/quickstart.rst +++ b/docs/quickstart.rst @@ -12,7 +12,7 @@ Update the settings file:: 'django.contrib.contenttypes', ) -The current release of *django-polymorphic* supports Django 1.11, 2.0 and Python 2.7 and 3.5+ is supported. +The current release of *django-polymorphic* supports Django 1.11, 2.0, 2.1, 2.2 and Python 2.7 and 3.5+ is supported. For older Django versions, use *django-polymorphic==1.3*. Making Your Models Polymorphic From b68a3b4e905d55445d43a8b9bb71d6e4636e5646 Mon Sep 17 00:00:00 2001 From: wfehr <24782511+wfehr@users.noreply.github.com> Date: Wed, 6 Nov 2019 08:22:43 +0100 Subject: [PATCH 02/30] Fixed typo in changelog --- docs/changelog.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index 426c0d4..f557280 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -1,7 +1,7 @@ Changelog ========= -Changes in 2.1.2 (2019-17-15) +Changes in 2.1.2 (2019-07-15) ----------------------------- * Fix ``PolymorphicInlineModelAdmin`` media jQuery include for Django 2.0+ From 37403c7421f08c96634f46d970acde969a60f454 Mon Sep 17 00:00:00 2001 From: Diederik van der Boor Date: Mon, 20 Jan 2020 09:34:49 +0100 Subject: [PATCH 03/30] Fix GitHub security alert for readthedocs deps --- docs/_ext/djangodummy/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/_ext/djangodummy/requirements.txt b/docs/_ext/djangodummy/requirements.txt index 62f1e49..639ed16 100644 --- a/docs/_ext/djangodummy/requirements.txt +++ b/docs/_ext/djangodummy/requirements.txt @@ -1,5 +1,5 @@ # for readthedocs # Remaining requirements are picked up from setup.py -Django == 2.2.3 +Django == 2.2.9 django-extra-views == 0.12.0 sphinxcontrib-django == 0.4 From 5db157c25478b92caaad7d8183141916895588c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Berthold=20H=C3=B6llmann?= Date: Sat, 23 May 2020 12:15:32 +0200 Subject: [PATCH 04/30] Fix `tox -e docs` for out or the box checkout. --- docs/_static/.gitkeep | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/_static/.gitkeep diff --git a/docs/_static/.gitkeep b/docs/_static/.gitkeep new file mode 100644 index 0000000..e69de29 From 59c1b03a9245e63e162cfa01641867d23a5e6ad4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 5 Jun 2020 17:51:33 +0000 Subject: [PATCH 05/30] Bump django from 2.2.9 to 2.2.13 in /docs/_ext/djangodummy Bumps [django](https://github.com/django/django) from 2.2.9 to 2.2.13. - [Release notes](https://github.com/django/django/releases) - [Commits](https://github.com/django/django/compare/2.2.9...2.2.13) Signed-off-by: dependabot[bot] --- docs/_ext/djangodummy/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/_ext/djangodummy/requirements.txt b/docs/_ext/djangodummy/requirements.txt index 639ed16..de7dbd2 100644 --- a/docs/_ext/djangodummy/requirements.txt +++ b/docs/_ext/djangodummy/requirements.txt @@ -1,5 +1,5 @@ # for readthedocs # Remaining requirements are picked up from setup.py -Django == 2.2.9 +Django == 2.2.13 django-extra-views == 0.12.0 sphinxcontrib-django == 0.4 From 8b35063f58ceade5d5af42f955ae2c0fdb7128fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Safa=20Ar=C4=B1man?= Date: Wed, 10 Jun 2020 10:56:36 +0300 Subject: [PATCH 06/30] Performance improvement on parentadmin --- polymorphic/admin/parentadmin.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/polymorphic/admin/parentadmin.py b/polymorphic/admin/parentadmin.py index c9f7598..c822966 100644 --- a/polymorphic/admin/parentadmin.py +++ b/polymorphic/admin/parentadmin.py @@ -146,13 +146,14 @@ class PolymorphicParentModelAdmin(admin.ModelAdmin): """ self._lazy_setup() choices = [] - for model in self.get_child_models(): + content_types = ContentType.objects.get_for_models(*self.get_child_models(), for_concrete_models=False) + + for model, ct in content_types.items(): perm_function_name = "has_{0}_permission".format(action) model_admin = self._get_real_admin_by_model(model) perm_function = getattr(model_admin, perm_function_name) if not perm_function(request): continue - ct = ContentType.objects.get_for_model(model, for_concrete_model=False) choices.append((ct.id, model._meta.verbose_name)) return choices From 10f65638528208af5e9b8207faad3eb406f61d0c Mon Sep 17 00:00:00 2001 From: Bastien Vallet Date: Tue, 4 Aug 2020 14:33:08 +0200 Subject: [PATCH 07/30] [compat] Cleanup compat matrix with Django/Python supported versions --- .travis.yml | 29 +++++++++++++++-------------- README.rst | 2 +- setup.cfg | 6 +++--- tox.ini | 11 +++++------ 4 files changed, 24 insertions(+), 24 deletions(-) diff --git a/.travis.yml b/.travis.yml index c320375..9edc4d6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,32 +11,33 @@ addons: matrix: fast_finish: true include: - # Django 1.11: Python 2.7, 3.5, or 3.6 - - { env: TOXENV=py27-django111, python: 2.7 } - - { env: TOXENV=py35-django111, python: 3.5 } - - { env: TOXENV=py36-django111, python: 3.6 } - - { env: TOXENV=py36-django111-postgres DB=postgres, python: 3.6 } - # Django 2.0: Python 3.5, or 3.6 - - { env: TOXENV=py35-django20, python: 3.5 } - - { env: TOXENV=py36-django20, python: 3.6 } - - { env: TOXENV=py36-django20-postgres DB=postgres, python: 3.6 } - # Django 2.1: Python 3.6, or 3.7 + # Django 2.1: Python 3.5, 3.6, or 3.7 + - { env: TOXENV=py35-django21, python: 3.5 } - { env: TOXENV=py36-django21, python: 3.6 } - { env: TOXENV=py37-django21, python: 3.7 } - { env: TOXENV=py37-django21-postgres DB=postgres, python: 3.7 } - # Django 2.2: Python 3.6, or 3.7 + # Django 2.2: Python 3.5, 3.6, 3.7 or 3.8 + - { env: TOXENV=py35-django22, python: 3.5 } - { env: TOXENV=py36-django22, python: 3.6 } - { env: TOXENV=py37-django22, python: 3.7 } - - { env: TOXENV=py37-django22-postgres DB=postgres, python: 3.7 } + - { env: TOXENV=py38-django22, python: 3.8 } + - { env: TOXENV=py38-django22-postgres DB=postgres, python: 3.8 } + # Django 3.0: Python 3.6, 3.7 or 3.8 + - { env: TOXENV=py36-django30, python: 3.6 } + - { env: TOXENV=py37-django30, python: 3.7 } + - { env: TOXENV=py38-django30, python: 3.8 } + - { env: TOXENV=py38-django30-postgres DB=postgres, python: 3.8 } # Django development master (direct from GitHub source): - { env: TOXENV=py36-djangomaster, python: 3.6 } - { env: TOXENV=py37-djangomaster, python: 3.7 } - - { env: TOXENV=py37-djangomaster-postgres DB=postgres, python: 3.7 } + - { env: TOXENV=py38-djangomaster, python: 3.8 } + - { env: TOXENV=py38-djangomaster-postgres DB=postgres, python: 3.8 } allow_failures: - env: TOXENV=py36-djangomaster - env: TOXENV=py37-djangomaster - - env: TOXENV=py37-djangomaster-postgres DB=postgres + - env: TOXENV=py38-djangomaster + - env: TOXENV=py38-djangomaster-postgres DB=postgres cache: directories: diff --git a/README.rst b/README.rst index 76a95b9..2905e12 100644 --- a/README.rst +++ b/README.rst @@ -62,7 +62,7 @@ Django to perform an ``INNER JOIN`` to fetch the model fields from the database. While taking this in mind, there are valid reasons for using subclassed models. That's what this library is designed for! -The current release of *django-polymorphic* supports Django 1.11, 2.0, 2.1, 2.2 and Python 2.7 and 3.5+ is supported. +The current release of *django-polymorphic* supports Django 2.1, 2.2, 3.0 and Python 3.5+ is supported. For older Django versions, install *django-polymorphic==1.3*. For more information, see the `documentation at Read the Docs `_. diff --git a/setup.cfg b/setup.cfg index a805f90..74740de 100644 --- a/setup.cfg +++ b/setup.cfg @@ -14,18 +14,18 @@ classifiers = Development Status :: 5 - Production/Stable Environment :: Web Environment Framework :: Django - Framework :: Django :: 1.11 - Framework :: Django :: 2.0 Framework :: Django :: 2.1 Framework :: Django :: 2.2 + Framework :: Django :: 3.0 Intended Audience :: Developers License :: OSI Approved :: BSD License Operating System :: OS Independent - Programming Language :: Python :: 2.7 Programming Language :: Python :: 3 + Programming Language :: Python :: 3 :: Only Programming Language :: Python :: 3.5 Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 + Programming Language :: Python :: 3.8 Topic :: Database [options] diff --git a/tox.ini b/tox.ini index 8ccc8fe..abe33ca 100644 --- a/tox.ini +++ b/tox.ini @@ -1,9 +1,9 @@ [tox] envlist = - py27-django{111} - py35-django{111,20} - py36-django{111,20,21,22,master} - py37-django{21,22,master} + py35-django{21,22,master} + py36-django{21,22,30,master} + py37-django{21,22,30,master} + py38-django{21,22,30,master} docs [testenv] @@ -14,10 +14,9 @@ setenv = deps = coverage dj-database-url - django111: Django >= 1.11, < 2.0 - django20: Django ~= 2.0 django21: Django ~= 2.1 django22: Django ~= 2.2 + django30: Django ~= 3.0 djangomaster: https://github.com/django/django/archive/master.tar.gz postgres: psycopg2 commands = From 85469082d0dcfac04ee92d205d8bee1a4c3aef4d Mon Sep 17 00:00:00 2001 From: Bastien Vallet Date: Tue, 4 Aug 2020 14:38:15 +0200 Subject: [PATCH 08/30] Remove python_2_unicode_compatible method --- example/orders/models.py | 3 --- polymorphic/compat.py | 19 ------------------- polymorphic/managers.py | 2 -- polymorphic/showfields.py | 2 -- 4 files changed, 26 deletions(-) diff --git a/example/orders/models.py b/example/orders/models.py index cf12286..97ec22e 100644 --- a/example/orders/models.py +++ b/example/orders/models.py @@ -1,12 +1,10 @@ from django.db import models from django.utils.dates import MONTHS_3 -from django.utils.six import python_2_unicode_compatible from django.utils.translation import ugettext_lazy as _ from polymorphic.models import PolymorphicModel -@python_2_unicode_compatible class Order(models.Model): """ An example order that has polymorphic relations @@ -23,7 +21,6 @@ class Order(models.Model): return self.title -@python_2_unicode_compatible class Payment(PolymorphicModel): """ A generic payment model. diff --git a/polymorphic/compat.py b/polymorphic/compat.py index e52a3a9..094b161 100644 --- a/polymorphic/compat.py +++ b/polymorphic/compat.py @@ -24,22 +24,3 @@ def with_metaclass(meta, *bases): return meta(name, bases, d) return type.__new__(metaclass, "temporary_class", (), {}) - - -def python_2_unicode_compatible(klass): - """ - A decorator that defines __unicode__ and __str__ methods under Python 2. - Under Python 3 it does nothing. - - To support Python 2 and 3 with a single code base, define a __str__ method - returning text and apply this decorator to the class. - """ - if PY2: - if "__str__" not in klass.__dict__: - raise ValueError( - "@python_2_unicode_compatible cannot be applied " - "to %s because it doesn't define __str__()." % klass.__name__ - ) - klass.__unicode__ = klass.__str__ - klass.__str__ = lambda self: self.__unicode__().encode("utf-8") - return klass diff --git a/polymorphic/managers.py b/polymorphic/managers.py index a43840b..901f086 100644 --- a/polymorphic/managers.py +++ b/polymorphic/managers.py @@ -6,13 +6,11 @@ from __future__ import unicode_literals from django.db import models -from polymorphic.compat import python_2_unicode_compatible from polymorphic.query import PolymorphicQuerySet __all__ = ("PolymorphicManager", "PolymorphicQuerySet") -@python_2_unicode_compatible class PolymorphicManager(models.Manager): """ Manager for PolymorphicModel diff --git a/polymorphic/showfields.py b/polymorphic/showfields.py index ffa14f5..0d62d88 100644 --- a/polymorphic/showfields.py +++ b/polymorphic/showfields.py @@ -4,12 +4,10 @@ import re from django.db import models from . import compat -from .compat import python_2_unicode_compatible RE_DEFERRED = re.compile("_Deferred_.*") -@python_2_unicode_compatible class ShowFieldBase(object): """ base class for the ShowField... model mixins, does the work """ From 68605ba2baee69367824e4b30aaa24b52e2c501b Mon Sep 17 00:00:00 2001 From: Bastien Vallet Date: Tue, 4 Aug 2020 14:43:07 +0200 Subject: [PATCH 09/30] [compat] Remove PY2 compat artefacts - No need to specific types - Remove __future__ imports --- docs/migrating.rst | 1 - polymorphic/admin/parentadmin.py | 18 +++--------------- polymorphic/base.py | 2 -- polymorphic/compat.py | 18 ------------------ polymorphic/contrib/extra_views.py | 2 -- polymorphic/managers.py | 1 - polymorphic/models.py | 2 -- polymorphic/query.py | 4 +--- polymorphic/query_translate.py | 4 +--- polymorphic/showfields.py | 2 +- .../templatetags/polymorphic_admin_tags.py | 2 +- polymorphic/tests/test_multidb.py | 2 -- polymorphic/utils.py | 9 ++------- 13 files changed, 9 insertions(+), 58 deletions(-) diff --git a/docs/migrating.rst b/docs/migrating.rst index 866da3b..2db2355 100644 --- a/docs/migrating.rst +++ b/docs/migrating.rst @@ -29,7 +29,6 @@ can be included in a single Django migration. For example: .. code-block:: python # -*- coding: utf-8 -*- - from __future__ import unicode_literals from django.db import migrations, models diff --git a/polymorphic/admin/parentadmin.py b/polymorphic/admin/parentadmin.py index c9f7598..7addfde 100644 --- a/polymorphic/admin/parentadmin.py +++ b/polymorphic/admin/parentadmin.py @@ -1,8 +1,6 @@ """ The parent admin displays the list view of the base model. """ -import sys - from django.contrib import admin from django.contrib.admin.helpers import AdminErrorList, AdminForm from django.contrib.admin.templatetags.admin_urls import add_preserved_filters @@ -11,6 +9,7 @@ from django.core.exceptions import ImproperlyConfigured, PermissionDenied from django.db import models from django.http import Http404, HttpResponseRedirect from django.template.response import TemplateResponse +from django.urls import URLResolver from django.utils.encoding import force_text from django.utils.http import urlencode from django.utils.safestring import mark_safe @@ -20,17 +19,6 @@ from polymorphic.utils import get_base_polymorphic_model from .forms import PolymorphicModelChoiceForm -try: - # Django 2.0+ - from django.urls import URLResolver -except ImportError: - # Django < 2.0 - from django.urls import RegexURLResolver as URLResolver - - -if sys.version_info[0] >= 3: - long = int - class RegistrationClosed(RuntimeError): "The admin model can't be registered anymore at this point." @@ -293,9 +281,9 @@ class PolymorphicParentModelAdmin(admin.ModelAdmin): try: pos = path.find("/") if pos == -1: - object_id = long(path) + object_id = int(path) else: - object_id = long(path[0:pos]) + object_id = int(path[0:pos]) except ValueError: raise Http404( "No ct_id parameter, unable to find admin subclass for path '{0}'.".format( diff --git a/polymorphic/base.py b/polymorphic/base.py index 81d988a..1bf6059 100644 --- a/polymorphic/base.py +++ b/polymorphic/base.py @@ -2,8 +2,6 @@ """ PolymorphicModel Meta Class """ -from __future__ import absolute_import - import inspect import os import sys diff --git a/polymorphic/compat.py b/polymorphic/compat.py index 094b161..1589eb2 100644 --- a/polymorphic/compat.py +++ b/polymorphic/compat.py @@ -1,22 +1,4 @@ """Compatibility with Python 2 (taken from 'django.utils.six')""" -import sys - -PY2 = sys.version_info[0] == 2 -PY3 = sys.version_info[0] == 3 - - -if PY3: - string_types = (str,) - integer_types = (int,) - class_types = (type,) - text_type = str - binary_type = bytes - - MAXSIZE = sys.maxsize -else: - string_types = (basestring,) - integer_types = (int, long) - def with_metaclass(meta, *bases): class metaclass(type): diff --git a/polymorphic/contrib/extra_views.py b/polymorphic/contrib/extra_views.py index f3e050d..9822c47 100644 --- a/polymorphic/contrib/extra_views.py +++ b/polymorphic/contrib/extra_views.py @@ -4,8 +4,6 @@ The ``extra_views.advanced`` provides a method to combine that with a create/upd This package provides classes that support both options for polymorphic formsets. """ -from __future__ import absolute_import - import extra_views from django.core.exceptions import ImproperlyConfigured diff --git a/polymorphic/managers.py b/polymorphic/managers.py index 901f086..5e894d4 100644 --- a/polymorphic/managers.py +++ b/polymorphic/managers.py @@ -2,7 +2,6 @@ """ The manager class for use in the models. """ -from __future__ import unicode_literals from django.db import models diff --git a/polymorphic/models.py b/polymorphic/models.py index 63731e8..5c34ff7 100644 --- a/polymorphic/models.py +++ b/polymorphic/models.py @@ -2,8 +2,6 @@ """ Seamless Polymorphic Inheritance for Django Models """ -from __future__ import absolute_import - from django.contrib.contenttypes.models import ContentType from django.db import models from django.db.models.fields.related import ( diff --git a/polymorphic/query.py b/polymorphic/query.py index 4dc4d30..7277f6c 100644 --- a/polymorphic/query.py +++ b/polymorphic/query.py @@ -2,8 +2,6 @@ """ QuerySet for PolymorphicModel """ -from __future__ import absolute_import - import copy from collections import defaultdict @@ -177,7 +175,7 @@ class PolymorphicQuerySet(QuerySet): """translate the field paths in the args, then call vanilla order_by.""" field_names = [ translate_polymorphic_field_path(self.model, a) - if isinstance(a, compat.string_types) + if isinstance(a, str) else a # allow expressions to pass unchanged for a in field_names ] diff --git a/polymorphic/query_translate.py b/polymorphic/query_translate.py index cbecf10..08798bc 100644 --- a/polymorphic/query_translate.py +++ b/polymorphic/query_translate.py @@ -2,8 +2,6 @@ """ PolymorphicQuerySet support functions """ -from __future__ import absolute_import - import copy from collections import deque @@ -144,7 +142,7 @@ def translate_polymorphic_field_path(queryset_model, field_path): into modela__modelb__modelc__field3. Returns: translated path (unchanged, if no translation needed) """ - if not isinstance(field_path, compat.string_types): + if not isinstance(field_path, str): raise ValueError("Expected field name as string: {0}".format(field_path)) classname, sep, pure_field_path = field_path.partition("___") diff --git a/polymorphic/showfields.py b/polymorphic/showfields.py index 0d62d88..d4c21b5 100644 --- a/polymorphic/showfields.py +++ b/polymorphic/showfields.py @@ -40,7 +40,7 @@ class ShowFieldBase(object): out += content.__class__.__name__ elif issubclass(field_type, models.ManyToManyField): out += "%d" % content.count() - elif isinstance(content, compat.integer_types): + elif isinstance(content, int): out += str(content) elif content is None: out += "None" diff --git a/polymorphic/templatetags/polymorphic_admin_tags.py b/polymorphic/templatetags/polymorphic_admin_tags.py index 9914b84..87057d6 100644 --- a/polymorphic/templatetags/polymorphic_admin_tags.py +++ b/polymorphic/templatetags/polymorphic_admin_tags.py @@ -31,7 +31,7 @@ class BreadcrumbScope(Node): # Instead, have an assignment tag that inserts that in the template. base_opts = self.base_opts.resolve(context) new_vars = {} - if base_opts and not isinstance(base_opts, compat.string_types): + if base_opts and not isinstance(base_opts, str): new_vars = { "app_label": base_opts.app_label, # What this is all about "opts": base_opts, diff --git a/polymorphic/tests/test_multidb.py b/polymorphic/tests/test_multidb.py index eec9e5a..b70a8d5 100644 --- a/polymorphic/tests/test_multidb.py +++ b/polymorphic/tests/test_multidb.py @@ -1,5 +1,3 @@ -from __future__ import print_function - from django.contrib.contenttypes.models import ContentType from django.db.models import Q from django.test import TestCase diff --git a/polymorphic/utils.py b/polymorphic/utils.py index 14c9a9f..8c00758 100644 --- a/polymorphic/utils.py +++ b/polymorphic/utils.py @@ -1,5 +1,3 @@ -import sys - from django.contrib.contenttypes.models import ContentType from django.db import DEFAULT_DB_ALIAS @@ -59,12 +57,9 @@ def sort_by_subclass(*classes): """ Sort a series of models by their inheritance order. """ - if sys.version_info[0] == 2: - return sorted(classes, cmp=_compare_mro) - else: - from functools import cmp_to_key + from functools import cmp_to_key - return sorted(classes, key=cmp_to_key(_compare_mro)) + return sorted(classes, key=cmp_to_key(_compare_mro)) def get_base_polymorphic_model(ChildModel, allow_abstract=False): From b6921baedee140ba3a5622080e6b8c5860f527f1 Mon Sep 17 00:00:00 2001 From: Bastien Vallet Date: Wed, 5 Aug 2020 10:39:48 +0200 Subject: [PATCH 10/30] Add support for Django 3.1 --- .travis.yml | 5 +++++ polymorphic/query.py | 2 +- polymorphic/query_translate.py | 4 ++-- setup.cfg | 1 + tox.ini | 7 ++++--- 5 files changed, 13 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9edc4d6..76a7e2d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,6 +27,11 @@ matrix: - { env: TOXENV=py37-django30, python: 3.7 } - { env: TOXENV=py38-django30, python: 3.8 } - { env: TOXENV=py38-django30-postgres DB=postgres, python: 3.8 } + # Django 3.1: Python 3.6, 3.7 or 3.8 + - { env: TOXENV=py36-django31, python: 3.6 } + - { env: TOXENV=py37-django31, python: 3.7 } + - { env: TOXENV=py38-django31, python: 3.8 } + - { env: TOXENV=py38-django31-postgres DB=postgres, python: 3.8 } # Django development master (direct from GitHub source): - { env: TOXENV=py36-djangomaster, python: 3.6 } - { env: TOXENV=py37-djangomaster, python: 3.7 } diff --git a/polymorphic/query.py b/polymorphic/query.py index 7277f6c..197fc0c 100644 --- a/polymorphic/query.py +++ b/polymorphic/query.py @@ -6,7 +6,7 @@ import copy from collections import defaultdict from django.contrib.contenttypes.models import ContentType -from django.db.models import FieldDoesNotExist +from django.core.exceptions import FieldDoesNotExist from django.db.models.query import ModelIterable, Q, QuerySet from . import compat diff --git a/polymorphic/query_translate.py b/polymorphic/query_translate.py index 08798bc..45328a9 100644 --- a/polymorphic/query_translate.py +++ b/polymorphic/query_translate.py @@ -7,7 +7,7 @@ from collections import deque from django.apps import apps from django.contrib.contenttypes.models import ContentType -from django.core.exceptions import FieldError +from django.core.exceptions import FieldError, FieldDoesNotExist from django.db import models from django.db.models import Q from django.db.models.fields.related import ForeignObjectRel, RelatedField @@ -187,7 +187,7 @@ def translate_polymorphic_field_path(queryset_model, field_path): # Can also test whether the field exists in the related object to avoid ambiguity between # class names and field names, but that never happens when your class names are in CamelCase. return field_path # No exception raised, field does exist. - except models.FieldDoesNotExist: + except FieldDoesNotExist: pass submodels = _get_all_sub_models(queryset_model) diff --git a/setup.cfg b/setup.cfg index 74740de..c6755cb 100644 --- a/setup.cfg +++ b/setup.cfg @@ -17,6 +17,7 @@ classifiers = Framework :: Django :: 2.1 Framework :: Django :: 2.2 Framework :: Django :: 3.0 + Framework :: Django :: 3.1 Intended Audience :: Developers License :: OSI Approved :: BSD License Operating System :: OS Independent diff --git a/tox.ini b/tox.ini index abe33ca..e507416 100644 --- a/tox.ini +++ b/tox.ini @@ -1,9 +1,9 @@ [tox] envlist = py35-django{21,22,master} - py36-django{21,22,30,master} - py37-django{21,22,30,master} - py38-django{21,22,30,master} + py36-django{21,22,30,31,master} + py37-django{21,22,30,31,master} + py38-django{21,22,30,31,master} docs [testenv] @@ -17,6 +17,7 @@ deps = django21: Django ~= 2.1 django22: Django ~= 2.2 django30: Django ~= 3.0 + django31: Django ~= 3.1 djangomaster: https://github.com/django/django/archive/master.tar.gz postgres: psycopg2 commands = From 7f248bd4bd1268b3491c6efcb37ac1dcf7e748b6 Mon Sep 17 00:00:00 2001 From: Bastien Vallet Date: Mon, 10 Aug 2020 22:48:31 +0200 Subject: [PATCH 11/30] Update README for Django compatibility list --- README.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 2905e12..15d49be 100644 --- a/README.rst +++ b/README.rst @@ -62,7 +62,8 @@ Django to perform an ``INNER JOIN`` to fetch the model fields from the database. While taking this in mind, there are valid reasons for using subclassed models. That's what this library is designed for! -The current release of *django-polymorphic* supports Django 2.1, 2.2, 3.0 and Python 3.5+ is supported. +The current release of *django-polymorphic* supports Django 2.1, 2.2, 3.0, 3.1 +and Python 3.5+ is supported. For older Django versions, install *django-polymorphic==1.3*. For more information, see the `documentation at Read the Docs `_. From 6be20c14bec6d9a47a665a9a6159afea7330cf95 Mon Sep 17 00:00:00 2001 From: Chris Glass Date: Fri, 14 Aug 2020 11:05:32 +0200 Subject: [PATCH 12/30] Fix PY3 reference in tests We only ever build for py3 now, the compat reference was useless. --- polymorphic/tests/test_orm.py | 38 +++++++++++------------------------ 1 file changed, 12 insertions(+), 26 deletions(-) diff --git a/polymorphic/tests/test_orm.py b/polymorphic/tests/test_orm.py index 62231f7..a0fd1e8 100644 --- a/polymorphic/tests/test_orm.py +++ b/polymorphic/tests/test_orm.py @@ -581,32 +581,18 @@ class PolymorphicTests(TransactionTestCase): select={"topic": "tests_modelextraexternal.topic"}, where=["tests_modelextraa.id = tests_modelextraexternal.id"], ) - if compat.PY3: - self.assertEqual( - repr(objects[0]), - '', - ) - self.assertEqual( - repr(objects[1]), - '', - ) - self.assertEqual( - repr(objects[2]), - '', - ) - else: - self.assertEqual( - repr(objects[0]), - '', - ) - self.assertEqual( - repr(objects[1]), - '', - ) - self.assertEqual( - repr(objects[2]), - '', - ) + self.assertEqual( + repr(objects[0]), + '', + ) + self.assertEqual( + repr(objects[1]), + '', + ) + self.assertEqual( + repr(objects[2]), + '', + ) self.assertEqual(len(objects), 3) def test_instance_of_filter(self): From c0874c5e90cfaef97f5b7a8014205966e27d668f Mon Sep 17 00:00:00 2001 From: Chris Glass Date: Fri, 14 Aug 2020 16:28:30 +0200 Subject: [PATCH 13/30] unrelated: add .venv to gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index bab3b71..c18fed3 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,4 @@ dist/ docs/_build/ htmlcov/ venv/ +.venv/ From 24dd1fff2cc33f06c1afc506385025173f0820da Mon Sep 17 00:00:00 2001 From: Chris Glass Date: Fri, 14 Aug 2020 16:29:49 +0200 Subject: [PATCH 14/30] Add ipdb to test deps This is not strictly necessary but it helps tremendously to have a REPL around to break into when a test fails. --- tox.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/tox.ini b/tox.ini index e507416..0c7f938 100644 --- a/tox.ini +++ b/tox.ini @@ -12,6 +12,7 @@ setenv = postgres: DEFAULT_DATABASE = postgres:///default postgres: SECONDARY_DATABASE = postgres:///secondary deps = + ipdb coverage dj-database-url django21: Django ~= 2.1 From 76871e3863a3358d2ec81767e7a936538d5ebf19 Mon Sep 17 00:00:00 2001 From: Chris Glass Date: Fri, 14 Aug 2020 16:32:18 +0200 Subject: [PATCH 15/30] Fix warnings This is a little uncertain - while it does fix warnings I'm not sure the removed assertion were actually useful in checking the behavior, and I'm not certain how to recreate the assertion without using the depracated path. --- polymorphic/tests/test_orm.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/polymorphic/tests/test_orm.py b/polymorphic/tests/test_orm.py index a0fd1e8..84da2a5 100644 --- a/polymorphic/tests/test_orm.py +++ b/polymorphic/tests/test_orm.py @@ -481,21 +481,22 @@ class PolymorphicTests(TransactionTestCase): def test_foreignkey_field(self): self.create_model2abcd() - object2a = Model2A.base_objects.get(field1="C1") + object2a = Model2A.objects.get(field1="C1") self.assertEqual(object2a.model2b.__class__, Model2B) - object2b = Model2B.base_objects.get(field1="C1") + object2b = Model2B.objects.get(field1="C1") self.assertEqual(object2b.model2c.__class__, Model2C) def test_onetoone_field(self): self.create_model2abcd() + # FIXME: We should not use base_objects here. a = Model2A.base_objects.get(field1="C1") b = One2OneRelatingModelDerived.objects.create( one2one=a, field1="f1", field2="f2" ) - # this result is basically wrong, probably due to Django cacheing (we used base_objects), but should not be a problem + # FIXME: this result is basically wrong, probably due to Django cacheing (we used base_objects), but should not be a problem self.assertEqual(b.one2one.__class__, Model2A) self.assertEqual(b.one2one_id, b.one2one.id) @@ -808,7 +809,6 @@ class PolymorphicTests(TransactionTestCase): self.assertIs(type(ModelWithMyManager.objects), MyManager) self.assertIs(type(ModelWithMyManager._default_manager), MyManager) - self.assertIs(type(ModelWithMyManager.base_objects), models.Manager) def test_user_defined_manager_as_secondary(self): self.create_model2abcd() @@ -831,7 +831,6 @@ class PolymorphicTests(TransactionTestCase): self.assertIs( type(ModelWithMyManagerNoDefault._default_manager), PolymorphicManager ) - self.assertIs(type(ModelWithMyManagerNoDefault.base_objects), models.Manager) def test_user_objects_manager_as_secondary(self): self.create_model2abcd() @@ -841,7 +840,6 @@ class PolymorphicTests(TransactionTestCase): self.assertIs(type(ModelWithMyManagerDefault.my_objects), MyManager) self.assertIs(type(ModelWithMyManagerDefault.objects), PolymorphicManager) self.assertIs(type(ModelWithMyManagerDefault._default_manager), MyManager) - self.assertIs(type(ModelWithMyManagerDefault.base_objects), models.Manager) def test_user_defined_queryset_as_manager(self): self.create_model2abcd() @@ -864,7 +862,6 @@ class PolymorphicTests(TransactionTestCase): type(ModelWithMyManager2._default_manager).__name__, "PolymorphicManagerFromMyManagerQuerySet", ) - self.assertIs(type(ModelWithMyManager2.base_objects), models.Manager) def test_manager_inheritance(self): # by choice of MRO, should be MyManager from MROBase1. From 0950478fcd556e89641c411eef3b562567d4981d Mon Sep 17 00:00:00 2001 From: Iacopo Spalletti Date: Fri, 14 Aug 2020 16:42:51 +0200 Subject: [PATCH 16/30] Update usage of databases instead of multidb --- polymorphic/tests/test_multidb.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/polymorphic/tests/test_multidb.py b/polymorphic/tests/test_multidb.py index b70a8d5..dee08d4 100644 --- a/polymorphic/tests/test_multidb.py +++ b/polymorphic/tests/test_multidb.py @@ -18,7 +18,7 @@ from polymorphic.tests.models import ( class MultipleDatabasesTests(TestCase): - multi_db = True + databases = ["default", "secondary"] def test_save_to_non_default_database(self): Model2A.objects.db_manager("secondary").create(field1="A1") From 76efd54df576d0869cd503ed750b938e09ac56a5 Mon Sep 17 00:00:00 2001 From: Iacopo Spalletti Date: Fri, 14 Aug 2020 16:48:12 +0200 Subject: [PATCH 17/30] Add missing field --- polymorphic/tests/migrations/0001_initial.py | 7 +++++++ polymorphic/tests/models.py | 1 + 2 files changed, 8 insertions(+) diff --git a/polymorphic/tests/migrations/0001_initial.py b/polymorphic/tests/migrations/0001_initial.py index 4707a36..38106a3 100644 --- a/polymorphic/tests/migrations/0001_initial.py +++ b/polymorphic/tests/migrations/0001_initial.py @@ -1450,6 +1450,13 @@ class Migration(migrations.Migration): to="tests.ParentModelWithManager", ), ), + migrations.AddField( + model_name="childmodelwithmanager", + name="field1", + field=models.CharField( + max_length=10, + ), + ), migrations.AddField( model_name="childmodelwithmanager", name="polymorphic_ctype", diff --git a/polymorphic/tests/models.py b/polymorphic/tests/models.py index 96e361f..494b98f 100644 --- a/polymorphic/tests/models.py +++ b/polymorphic/tests/models.py @@ -222,6 +222,7 @@ class ParentModelWithManager(PolymorphicModel): class ChildModelWithManager(PolymorphicModel): # Also test whether foreign keys receive the manager: + field1 = models.CharField(max_length=10) # needed as MyManager uses it fk = models.ForeignKey( ParentModelWithManager, on_delete=models.CASCADE, related_name="childmodel_set" ) From 7f839aaa361ca87afcdac55d2c4d61122a78fa21 Mon Sep 17 00:00:00 2001 From: Chris Glass Date: Fri, 14 Aug 2020 17:02:40 +0200 Subject: [PATCH 18/30] Remove django master from env list When running locally, don't test against django master. The travis config will however still test those. --- tox.ini | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tox.ini b/tox.ini index 0c7f938..2e4d2c3 100644 --- a/tox.ini +++ b/tox.ini @@ -1,9 +1,9 @@ [tox] envlist = - py35-django{21,22,master} - py36-django{21,22,30,31,master} - py37-django{21,22,30,31,master} - py38-django{21,22,30,31,master} + py35-django{21,22} + py36-django{21,22,30,31} + py37-django{21,22,30,31} + py38-django{21,22,30,31} docs [testenv] From 1e2c880429765984b7eec28cab06e0aebd3f3d55 Mon Sep 17 00:00:00 2001 From: Iacopo Spalletti Date: Fri, 14 Aug 2020 17:46:32 +0200 Subject: [PATCH 19/30] Add explicit SECRET_KEY required by django master --- runtests.py | 1 + 1 file changed, 1 insertion(+) diff --git a/runtests.py b/runtests.py index 75a7253..ac8d9f1 100755 --- a/runtests.py +++ b/runtests.py @@ -74,6 +74,7 @@ if not settings.configured: ], POLYMORPHIC_TEST_SWAPPABLE="polymorphic.swappedmodel", ROOT_URLCONF=None, + SECRET_KEY="supersecret" ) From 1d719a0e605632bb761fb002673c5530896e6f32 Mon Sep 17 00:00:00 2001 From: Chris Glass Date: Tue, 18 Aug 2020 10:04:58 +0200 Subject: [PATCH 20/30] Remove unused imports A few places still imported the compat module for no reason - this commit fixes that. --- polymorphic/query.py | 1 - polymorphic/showfields.py | 2 -- polymorphic/templatetags/polymorphic_admin_tags.py | 2 -- 3 files changed, 5 deletions(-) diff --git a/polymorphic/query.py b/polymorphic/query.py index 197fc0c..a86b2dc 100644 --- a/polymorphic/query.py +++ b/polymorphic/query.py @@ -9,7 +9,6 @@ from django.contrib.contenttypes.models import ContentType from django.core.exceptions import FieldDoesNotExist from django.db.models.query import ModelIterable, Q, QuerySet -from . import compat from .query_translate import ( translate_polymorphic_field_path, translate_polymorphic_filter_definitions_in_args, diff --git a/polymorphic/showfields.py b/polymorphic/showfields.py index d4c21b5..8da8330 100644 --- a/polymorphic/showfields.py +++ b/polymorphic/showfields.py @@ -3,8 +3,6 @@ import re from django.db import models -from . import compat - RE_DEFERRED = re.compile("_Deferred_.*") diff --git a/polymorphic/templatetags/polymorphic_admin_tags.py b/polymorphic/templatetags/polymorphic_admin_tags.py index 87057d6..aa68843 100644 --- a/polymorphic/templatetags/polymorphic_admin_tags.py +++ b/polymorphic/templatetags/polymorphic_admin_tags.py @@ -1,7 +1,5 @@ from django.template import Library, Node, TemplateSyntaxError -from polymorphic import compat - register = Library() From 49c2abf70d33332f1b26c3bb27659f0fe48796d0 Mon Sep 17 00:00:00 2001 From: Iacopo Spalletti Date: Tue, 18 Aug 2020 12:34:55 +0200 Subject: [PATCH 21/30] Replace ugettext with gettext to fix deprecation warnings --- polymorphic/admin/childadmin.py | 2 +- polymorphic/admin/filters.py | 2 +- polymorphic/admin/forms.py | 2 +- polymorphic/admin/helpers.py | 6 +++--- polymorphic/admin/parentadmin.py | 2 +- polymorphic/templatetags/polymorphic_formset_tags.py | 6 +++--- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/polymorphic/admin/childadmin.py b/polymorphic/admin/childadmin.py index cd20773..5e9b17d 100644 --- a/polymorphic/admin/childadmin.py +++ b/polymorphic/admin/childadmin.py @@ -5,7 +5,7 @@ import inspect from django.contrib import admin from django.urls import resolve -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from polymorphic.utils import get_base_polymorphic_model diff --git a/polymorphic/admin/filters.py b/polymorphic/admin/filters.py index 171599b..37efc7f 100644 --- a/polymorphic/admin/filters.py +++ b/polymorphic/admin/filters.py @@ -1,6 +1,6 @@ from django.contrib import admin from django.core.exceptions import PermissionDenied -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ class PolymorphicChildModelFilter(admin.SimpleListFilter): diff --git a/polymorphic/admin/forms.py b/polymorphic/admin/forms.py index 08e950f..8a705f0 100644 --- a/polymorphic/admin/forms.py +++ b/polymorphic/admin/forms.py @@ -1,6 +1,6 @@ from django import forms from django.contrib.admin.widgets import AdminRadioSelect -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ class PolymorphicModelChoiceForm(forms.Form): diff --git a/polymorphic/admin/helpers.py b/polymorphic/admin/helpers.py index 122f467..130ef31 100644 --- a/polymorphic/admin/helpers.py +++ b/polymorphic/admin/helpers.py @@ -8,7 +8,7 @@ import json from django.contrib.admin.helpers import AdminField, InlineAdminForm, InlineAdminFormSet from django.utils.encoding import force_text from django.utils.text import capfirst -from django.utils.translation import ugettext +from django.utils.translation import gettext from polymorphic.formsets import BasePolymorphicModelFormSet @@ -96,7 +96,7 @@ class PolymorphicInlineAdminFormSet(InlineAdminFormSet): "name": "#%s" % self.formset.prefix, "options": { "prefix": self.formset.prefix, - "addText": ugettext("Add another %(verbose_name)s") + "addText": gettext("Add another %(verbose_name)s") % {"verbose_name": capfirst(verbose_name)}, "childTypes": [ { @@ -105,7 +105,7 @@ class PolymorphicInlineAdminFormSet(InlineAdminFormSet): } for model in self.formset.child_forms.keys() ], - "deleteText": ugettext("Remove"), + "deleteText": gettext("Remove"), }, } ) diff --git a/polymorphic/admin/parentadmin.py b/polymorphic/admin/parentadmin.py index 8f71e6a..f56bde8 100644 --- a/polymorphic/admin/parentadmin.py +++ b/polymorphic/admin/parentadmin.py @@ -13,7 +13,7 @@ from django.urls import URLResolver from django.utils.encoding import force_text from django.utils.http import urlencode from django.utils.safestring import mark_safe -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from polymorphic.utils import get_base_polymorphic_model diff --git a/polymorphic/templatetags/polymorphic_formset_tags.py b/polymorphic/templatetags/polymorphic_formset_tags.py index 6a78eca..0b2895f 100644 --- a/polymorphic/templatetags/polymorphic_formset_tags.py +++ b/polymorphic/templatetags/polymorphic_formset_tags.py @@ -3,7 +3,7 @@ import json from django.template import Library from django.utils.encoding import force_text from django.utils.text import capfirst -from django.utils.translation import ugettext +from django.utils.translation import gettext from polymorphic.formsets import BasePolymorphicModelFormSet @@ -44,10 +44,10 @@ def as_script_options(formset): "prefix": formset.prefix, "pkFieldName": formset.model._meta.pk.name, "addText": getattr(formset, "add_text", None) - or ugettext("Add another %(verbose_name)s") + or gettext("Add another %(verbose_name)s") % {"verbose_name": capfirst(verbose_name)}, "showAddButton": getattr(formset, "show_add_button", True), - "deleteText": ugettext("Delete"), + "deleteText": gettext("Delete"), } if isinstance(formset, BasePolymorphicModelFormSet): From c512759274f9006f0bb0288ab1b06ed399e911c2 Mon Sep 17 00:00:00 2001 From: Bastien Vallet Date: Sat, 15 Aug 2020 22:43:09 +0200 Subject: [PATCH 22/30] [misc] Various cleanup - Adding in AUTHORS file - Fix minimal Django version in setup - Remove deprecated options in travis config --- .travis.yml | 3 --- AUTHORS.rst | 1 + setup.cfg | 2 +- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 76a7e2d..80cf127 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,3 @@ -# https://travis-ci.org/django-polymorphic/django-polymorphic -dist: xenial -sudo: false language: python services: diff --git a/AUTHORS.rst b/AUTHORS.rst index 81590be..93bd537 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -19,6 +19,7 @@ Contributors * Andrew Dodd * Angel Velasquez * Austin Matsick +* Bastien Vallet * Ben Konrath * Bert Constantin * Bertrand Bordage diff --git a/setup.cfg b/setup.cfg index c6755cb..8adea1e 100644 --- a/setup.cfg +++ b/setup.cfg @@ -33,7 +33,7 @@ classifiers = packages = find: include_package_data = True install_requires = - Django >= 1.11 + Django >= 2.1 [options.packages.find] exclude = From 60ea5524b841540d1ea60c85ab4fdddde62b3d75 Mon Sep 17 00:00:00 2001 From: Chris Glass Date: Tue, 18 Aug 2020 15:54:45 +0200 Subject: [PATCH 23/30] Make test_defer_fields use get_deferred_fields() Use the provided get_deferred_fields() method instead of relying on the repr() for the objects to determine whether a field is deferred or not. --- polymorphic/tests/test_orm.py | 77 +++++++++++++---------------------- 1 file changed, 28 insertions(+), 49 deletions(-) diff --git a/polymorphic/tests/test_orm.py b/polymorphic/tests/test_orm.py index 84da2a5..8a55c8e 100644 --- a/polymorphic/tests/test_orm.py +++ b/polymorphic/tests/test_orm.py @@ -238,22 +238,12 @@ class PolymorphicTests(TransactionTestCase): objects_deferred[0].__dict__, "field1 was not deferred (using defer())", ) - self.assertRegex( - repr(objects_deferred[0]), - r"", - ) - self.assertRegex( - repr(objects_deferred[1]), - r"", - ) - self.assertRegex( - repr(objects_deferred[2]), - r"", - ) - self.assertRegex( - repr(objects_deferred[3]), - r"", - ) + + # Check that we have exactly one deferred field ('field1') per resulting object. + for obj in objects_deferred: + deferred_fields = obj.get_deferred_fields() + self.assertEqual(1, len(deferred_fields)) + self.assertIn("field1", deferred_fields) objects_only = Model2A.objects.only("pk", "polymorphic_ctype", "field1") @@ -271,48 +261,37 @@ class PolymorphicTests(TransactionTestCase): self.assertNotIn( "field4", objects_only[3].__dict__, "field4 was not deferred (using only())" ) - self.assertRegex( - repr(objects_only[0]), r"" - ) - self.assertRegex( - repr(objects_only[1]), - r"", - ) - self.assertRegex( - repr(objects_only[2]), - r"", - ) - self.assertRegex( - repr(objects_only[3]), - r"", - ) + self.assertNotIn("field1", objects_only[0].get_deferred_fields()) + + self.assertIn("field2", objects_only[1].get_deferred_fields()) + + # objects_only[2] has several deferred fields, ensure they are all set as such. + model2c_deferred = objects_only[2].get_deferred_fields() + self.assertIn("field2", model2c_deferred) + self.assertIn("field3", model2c_deferred) + self.assertIn("model2a_ptr_id", model2c_deferred) + + # objects_only[3] has a few more fields that should be set as deferred. + model2d_deferred = objects_only[3].get_deferred_fields() + self.assertIn("field2", model2d_deferred) + self.assertIn("field3", model2d_deferred) + self.assertIn("field4", model2d_deferred) + self.assertIn("model2a_ptr_id", model2d_deferred) + self.assertIn("model2b_ptr_id", model2d_deferred) ModelX.objects.create(field_b="A1", field_x="A2") ModelY.objects.create(field_b="B1", field_y="B2") + # If we defer a field on a descendent, the parent's field is not deferred. objects_deferred = Base.objects.defer("ModelY___field_y") - self.assertRegex( - repr(objects_deferred[0]), - r"", - ) - self.assertRegex( - repr(objects_deferred[1]), - r"", - ) + self.assertNotIn("field_y", objects_deferred[0].get_deferred_fields()) + self.assertIn("field_y", objects_deferred[1].get_deferred_fields()) objects_only = Base.objects.only( "polymorphic_ctype", "ModelY___field_y", "ModelX___field_x" ) - self.assertRegex( - repr(objects_only[0]), - r"", - ) - self.assertRegex( - repr(objects_only[1]), - r"", - ) + self.assertIn("field_b", objects_only[0].get_deferred_fields()) + self.assertIn("field_b", objects_only[1].get_deferred_fields()) def test_defer_related_fields(self): self.create_model2abcd() From 69bbe58dc7312880a737d14b641ee54d5e12b6d9 Mon Sep 17 00:00:00 2001 From: Chris Glass Date: Tue, 18 Aug 2020 16:30:59 +0200 Subject: [PATCH 24/30] Travis should run everywhere --- .travis.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 80cf127..42a2019 100644 --- a/.travis.yml +++ b/.travis.yml @@ -60,7 +60,3 @@ script: after_success: - coverage xml -i - codecov - -branches: - only: - - master From 0232befbae68e0e9cb7840411d321e800b2b5347 Mon Sep 17 00:00:00 2001 From: Adam Donaghy Date: Wed, 19 Aug 2020 14:00:53 +1000 Subject: [PATCH 25/30] Attempted fix for failures on master --- polymorphic/query.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/polymorphic/query.py b/polymorphic/query.py index a86b2dc..c2cc78f 100644 --- a/polymorphic/query.py +++ b/polymorphic/query.py @@ -157,7 +157,7 @@ class PolymorphicQuerySet(QuerySet): # Implementation in _translate_polymorphic_filter_defnition.""" return self.filter(not_instance_of=args) - def _filter_or_exclude(self, negate, *args, **kwargs): + def _filter_or_exclude(self, negate, args, kwargs): # We override this internal Django functon as it is used for all filter member functions. q_objects = translate_polymorphic_filter_definitions_in_args( self.model, args, using=self.db @@ -167,7 +167,7 @@ class PolymorphicQuerySet(QuerySet): self.model, kwargs, using=self.db ) return super(PolymorphicQuerySet, self)._filter_or_exclude( - negate, *(list(q_objects) + additional_args), **kwargs + negate, (list(q_objects) + additional_args), kwargs ) def order_by(self, *field_names): From 21f635d65abd3ddff8edd9077f82d0f56f431da8 Mon Sep 17 00:00:00 2001 From: Adam Donaghy Date: Wed, 19 Aug 2020 17:36:39 +1000 Subject: [PATCH 26/30] Backwards compatible _filter_or_exclude --- AUTHORS.rst | 1 + polymorphic/query.py | 22 ++++++++++++++++++++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/AUTHORS.rst b/AUTHORS.rst index 93bd537..0d7efd1 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -13,6 +13,7 @@ Contributors * Abel Daniel * Adam Chainz * Adam Wentz +* Adam Donaghy * Andrew Ingram (contributed setup.py) * Al Johri * Alex Alvarez diff --git a/polymorphic/query.py b/polymorphic/query.py index c2cc78f..6f979bc 100644 --- a/polymorphic/query.py +++ b/polymorphic/query.py @@ -5,6 +5,7 @@ QuerySet for PolymorphicModel import copy from collections import defaultdict +from django import get_version as get_django_version from django.contrib.contenttypes.models import ContentType from django.core.exceptions import FieldDoesNotExist from django.db.models.query import ModelIterable, Q, QuerySet @@ -157,7 +158,7 @@ class PolymorphicQuerySet(QuerySet): # Implementation in _translate_polymorphic_filter_defnition.""" return self.filter(not_instance_of=args) - def _filter_or_exclude(self, negate, args, kwargs): + def _filter_or_exclude(self, negate, *args, **kwargs): # We override this internal Django functon as it is used for all filter member functions. q_objects = translate_polymorphic_filter_definitions_in_args( self.model, args, using=self.db @@ -167,7 +168,7 @@ class PolymorphicQuerySet(QuerySet): self.model, kwargs, using=self.db ) return super(PolymorphicQuerySet, self)._filter_or_exclude( - negate, (list(q_objects) + additional_args), kwargs + negate, *(list(q_objects) + additional_args), **kwargs ) def order_by(self, *field_names): @@ -522,3 +523,20 @@ class PolymorphicQuerySet(QuerySet): return olist clist = PolymorphicQuerySet._p_list_class(olist) return clist + + +if get_django_version() > "3.2": + class PolymorphicQuerySet(PolymorphicQuerySet): + def _filter_or_exclude(self, negate, args, kwargs): + # We override this internal Django functon as it is used for all filter member functions. + q_objects = translate_polymorphic_filter_definitions_in_args( + queryset_model=self.model, args=args, using=self.db + ) + # filter_field='data' + additional_args = translate_polymorphic_filter_definitions_in_kwargs( + queryset_model=self.model, kwargs=kwargs, using=self.db + ) + args = list(q_objects) + additional_args + return super(PolymorphicQuerySet, self)._filter_or_exclude( + negate=negate, args=args, kwargs=kwargs + ) \ No newline at end of file From d93f17846fb8a36c9f2bd83a80e0729297d4394f Mon Sep 17 00:00:00 2001 From: Adam Donaghy Date: Wed, 19 Aug 2020 18:04:20 +1000 Subject: [PATCH 27/30] Side load _filter_or_exclude to avoid recursion --- polymorphic/query.py | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/polymorphic/query.py b/polymorphic/query.py index 6f979bc..ea44813 100644 --- a/polymorphic/query.py +++ b/polymorphic/query.py @@ -525,18 +525,18 @@ class PolymorphicQuerySet(QuerySet): return clist -if get_django_version() > "3.2": - class PolymorphicQuerySet(PolymorphicQuerySet): - def _filter_or_exclude(self, negate, args, kwargs): - # We override this internal Django functon as it is used for all filter member functions. - q_objects = translate_polymorphic_filter_definitions_in_args( - queryset_model=self.model, args=args, using=self.db - ) - # filter_field='data' - additional_args = translate_polymorphic_filter_definitions_in_kwargs( - queryset_model=self.model, kwargs=kwargs, using=self.db - ) - args = list(q_objects) + additional_args - return super(PolymorphicQuerySet, self)._filter_or_exclude( - negate=negate, args=args, kwargs=kwargs - ) \ No newline at end of file +if get_django_version() >= "3.2": + def _filter_or_exclude(self, negate, args, kwargs): + # We override this internal Django functon as it is used for all filter member functions. + q_objects = translate_polymorphic_filter_definitions_in_args( + queryset_model=self.model, args=args, using=self.db + ) + # filter_field='data' + additional_args = translate_polymorphic_filter_definitions_in_kwargs( + queryset_model=self.model, kwargs=kwargs, using=self.db + ) + args = list(q_objects) + additional_args + return super(PolymorphicQuerySet, self)._filter_or_exclude( + negate=negate, args=args, kwargs=kwargs + ) + PolymorphicQuerySet._filter_or_exclude = _filter_or_exclude From 45215ff6c3d4538f49edecaf8573d74ec2eff6d0 Mon Sep 17 00:00:00 2001 From: Adam Donaghy Date: Wed, 19 Aug 2020 18:23:49 +1000 Subject: [PATCH 28/30] Add little docstring and typo fix --- polymorphic/query.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/polymorphic/query.py b/polymorphic/query.py index ea44813..54ee0ee 100644 --- a/polymorphic/query.py +++ b/polymorphic/query.py @@ -159,7 +159,7 @@ class PolymorphicQuerySet(QuerySet): return self.filter(not_instance_of=args) def _filter_or_exclude(self, negate, *args, **kwargs): - # We override this internal Django functon as it is used for all filter member functions. + # We override this internal Django function as it is used for all filter member functions. q_objects = translate_polymorphic_filter_definitions_in_args( self.model, args, using=self.db ) @@ -525,9 +525,10 @@ class PolymorphicQuerySet(QuerySet): return clist +# Makes _filter_or_exclude compatible with the change in signature introduced in django at 9c9a3fe if get_django_version() >= "3.2": def _filter_or_exclude(self, negate, args, kwargs): - # We override this internal Django functon as it is used for all filter member functions. + # We override this internal Django function as it is used for all filter member functions. q_objects = translate_polymorphic_filter_definitions_in_args( queryset_model=self.model, args=args, using=self.db ) From fa6808e9b35622bef7fd6d038ea61c4eaf5ee8c7 Mon Sep 17 00:00:00 2001 From: Adam Donaghy Date: Thu, 20 Aug 2020 12:34:17 +1000 Subject: [PATCH 29/30] Use conditional function definition --- polymorphic/query.py | 60 +++++++++++++++++++++----------------------- 1 file changed, 29 insertions(+), 31 deletions(-) diff --git a/polymorphic/query.py b/polymorphic/query.py index 54ee0ee..8b0259b 100644 --- a/polymorphic/query.py +++ b/polymorphic/query.py @@ -158,18 +158,34 @@ class PolymorphicQuerySet(QuerySet): # Implementation in _translate_polymorphic_filter_defnition.""" return self.filter(not_instance_of=args) - def _filter_or_exclude(self, negate, *args, **kwargs): - # We override this internal Django function as it is used for all filter member functions. - q_objects = translate_polymorphic_filter_definitions_in_args( - self.model, args, using=self.db - ) - # filter_field='data' - additional_args = translate_polymorphic_filter_definitions_in_kwargs( - self.model, kwargs, using=self.db - ) - return super(PolymorphicQuerySet, self)._filter_or_exclude( - negate, *(list(q_objects) + additional_args), **kwargs - ) + # Makes _filter_or_exclude compatible with the change in signature introduced in django at 9c9a3fe + if get_django_version() >= "3.2": + def _filter_or_exclude(self, negate, args, kwargs): + # We override this internal Django function as it is used for all filter member functions. + q_objects = translate_polymorphic_filter_definitions_in_args( + queryset_model=self.model, args=args, using=self.db + ) + # filter_field='data' + additional_args = translate_polymorphic_filter_definitions_in_kwargs( + queryset_model=self.model, kwargs=kwargs, using=self.db + ) + args = list(q_objects) + additional_args + return super(PolymorphicQuerySet, self)._filter_or_exclude( + negate=negate, args=args, kwargs=kwargs + ) + else: + def _filter_or_exclude(self, negate, *args, **kwargs): + # We override this internal Django function as it is used for all filter member functions. + q_objects = translate_polymorphic_filter_definitions_in_args( + self.model, args, using=self.db + ) + # filter_field='data' + additional_args = translate_polymorphic_filter_definitions_in_kwargs( + self.model, kwargs, using=self.db + ) + return super(PolymorphicQuerySet, self)._filter_or_exclude( + negate, *(list(q_objects) + additional_args), **kwargs + ) def order_by(self, *field_names): """translate the field paths in the args, then call vanilla order_by.""" @@ -522,22 +538,4 @@ class PolymorphicQuerySet(QuerySet): if not self.model.polymorphic_query_multiline_output: return olist clist = PolymorphicQuerySet._p_list_class(olist) - return clist - - -# Makes _filter_or_exclude compatible with the change in signature introduced in django at 9c9a3fe -if get_django_version() >= "3.2": - def _filter_or_exclude(self, negate, args, kwargs): - # We override this internal Django function as it is used for all filter member functions. - q_objects = translate_polymorphic_filter_definitions_in_args( - queryset_model=self.model, args=args, using=self.db - ) - # filter_field='data' - additional_args = translate_polymorphic_filter_definitions_in_kwargs( - queryset_model=self.model, kwargs=kwargs, using=self.db - ) - args = list(q_objects) + additional_args - return super(PolymorphicQuerySet, self)._filter_or_exclude( - negate=negate, args=args, kwargs=kwargs - ) - PolymorphicQuerySet._filter_or_exclude = _filter_or_exclude + return clist \ No newline at end of file From b4efb59cd5d6b1ce3e10fdb5c495fbe239d91ad7 Mon Sep 17 00:00:00 2001 From: Chris Glass Date: Fri, 21 Aug 2020 12:31:07 +0200 Subject: [PATCH 30/30] Release 3.0.0 --- docs/changelog.rst | 7 +++++++ setup.cfg | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index f557280..f086aad 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -1,6 +1,13 @@ Changelog ========= +Changes in 3.0.0 (2020-08-21) +----------------------------- + +* Support for Django 3.X +* Dropped support for python 2.X +* A lot of various fixes and improvements by various authors. Thanks a lot! + Changes in 2.1.2 (2019-07-15) ----------------------------- diff --git a/setup.cfg b/setup.cfg index 8adea1e..a576a6e 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,12 +1,12 @@ [metadata] name = django-polymorphic -version = 2.1.2 +version = 3.0.0 description = Seamless polymorphic inheritance for Django models long_description = file:README.rst author = Bert Constantin author_email = bert.constantin@gmx.de maintainer = Christopher Glass -maintainer_email = tribaal@gmail.com +maintainer_email = tribaal@ubuntu.com url = https://github.com/django-polymorphic/django-polymorphic download_url = https://github.com/django-polymorphic/django-polymorphic/tarball/master keywords = django, polymorphic