diff --git a/.travis.yml b/.travis.yml
index a621d1d..9a3175a 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -5,17 +5,18 @@ language: python
python: "3.6"
env:
- - TOXENV=py27-django110
- TOXENV=py27-django111
- - TOXENV=py34-django110
- TOXENV=py34-django111
- - TOXENV=py35-django110
+ - TOXENV=py34-django200
- TOXENV=py35-django111
+ - TOXENV=py35-django200
- TOXENV=py35-djangomaster
- TOXENV=py36-django111
+ - TOXENV=py36-django200
- TOXENV=py36-djangomaster
# XXX: Use a matrix to build these?
- TOXENV=py36-django111-postgres DB=postgres
+ - TOXENV=py36-django200-postgres DB=postgres
- TOXENV=py36-djangomaster-postgres DB=postgres
services:
@@ -24,17 +25,21 @@ services:
matrix:
fast_finish: true
include:
- - python: "3.5"
- env: TOXENV=py35-django110
+ - python: "2.7"
+ env: TOXENV=py27-django111
- python: "3.5"
env: TOXENV=py35-django111
+ - python: "3.5"
+ env: TOXENV=py35-django200
- python: "3.5"
env: TOXENV=py35-djangomaster
exclude:
- python: "3.6"
- env: TOXENV=py35-django110
+ env: TOXENV=py27-django111
- python: "3.6"
env: TOXENV=py35-django111
+ - python: "3.6"
+ env: TOXENV=py35-django200
- python: "3.6"
env: TOXENV=py35-djangomaster
allow_failures:
diff --git a/README.rst b/README.rst
index 5b67d04..3d96553 100644
--- a/README.rst
+++ b/README.rst
@@ -60,8 +60,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 1.8, 1.10, 1.11 and Python 2.7 and 3.4+ is supported.
-For older Django versions, install *django-polymorphic==1.2*.
+The current release of *django-polymorphic* supports Django 1.11, 2.0 and Python 2.7 and 3.4+ is supported.
+For older Django versions, install *django-polymorphic==1.3*.
For more information, see the `documentation at Read the Docs `_.
diff --git a/docs/changelog.rst b/docs/changelog.rst
index bc242ab..ded13c1 100644
--- a/docs/changelog.rst
+++ b/docs/changelog.rst
@@ -4,13 +4,14 @@ Changelog
Changes in git
--------------
-* **BACKWARDS INCOMPATIBILITY:** Dropped Django 1.8 support.
+* **BACKWARDS INCOMPATIBILITY:** Dropped Django 1.8 and 1.10 support.
* **BACKWARDS INCOMPATIBILITY:** Removed old deprecated code from 1.0, thus:
* Import managers from ``polymorphic.managers`` (plural), not ``polymorphic.manager``.
* Register child models to the admin as well using ``@admin.register()`` or ``admin.site.register()``,
as this is no longer done automatically.
+* Django 2.0 support.
* Added ``PolymorphicTypeUndefined`` exception for incomplete imported models.
When a data migration or import creates an polymorphic model,
the ``polymorphic_ctype_id`` field should be filled in manually too.
diff --git a/docs/quickstart.rst b/docs/quickstart.rst
index 3df803f..91ca7b3 100644
--- a/docs/quickstart.rst
+++ b/docs/quickstart.rst
@@ -12,8 +12,8 @@ Update the settings file::
'django.contrib.contenttypes',
)
-The current release of *django-polymorphic* supports Django 1.8, 1.10, 1.11 and Python 2.7 and 3.4+ is supported.
-For older Django versions, use *django-polymorphic==1.2*.
+The current release of *django-polymorphic* supports Django 1.11, 2.0 and Python 2.7 and 3.4+ is supported.
+For older Django versions, use *django-polymorphic==1.3*.
Making Your Models Polymorphic
------------------------------
diff --git a/polymorphic/admin/parentadmin.py b/polymorphic/admin/parentadmin.py
index 00dcb34..32fb3a9 100644
--- a/polymorphic/admin/parentadmin.py
+++ b/polymorphic/admin/parentadmin.py
@@ -11,16 +11,22 @@ from django.core.exceptions import PermissionDenied, ImproperlyConfigured
from django.db import models
from django.http import Http404, HttpResponseRedirect
from django.template.response import TemplateResponse
-from django.urls import RegexURLResolver
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 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
@@ -265,7 +271,7 @@ class PolymorphicParentModelAdmin(admin.ModelAdmin):
ct_id = self.model.objects.values_list('polymorphic_ctype_id', flat=True).get(pk=object_id)
real_admin = self._get_real_admin_by_ct(ct_id)
- resolver = RegexURLResolver('^', real_admin.urls)
+ resolver = URLResolver('^', real_admin.urls)
resolvermatch = resolver.resolve(path) # May raise Resolver404
if not resolvermatch:
raise Http404("No match for path '{0}' in admin subclass.".format(path))
diff --git a/polymorphic/formsets/utils.py b/polymorphic/formsets/utils.py
index 3d55f8b..5dac6a7 100644
--- a/polymorphic/formsets/utils.py
+++ b/polymorphic/formsets/utils.py
@@ -1,11 +1,17 @@
"""
Internal utils
"""
+import django
def add_media(dest, media):
"""
Optimized version of django.forms.Media.__add__() that doesn't create new objects.
+
+ Only required for Django < 2.0
"""
- dest.add_css(media._css)
- dest.add_js(media._js)
+ if django.VERSION >= (2, 0):
+ dest += media
+ else:
+ dest.add_css(media._css)
+ dest.add_js(media._js)
diff --git a/polymorphic/models.py b/polymorphic/models.py
index 6c7a9b4..893dddd 100644
--- a/polymorphic/models.py
+++ b/polymorphic/models.py
@@ -6,6 +6,7 @@ from __future__ import absolute_import
from django.contrib.contenttypes.models import ContentType
from django.db import models
+from django.db.models.fields.related import ReverseOneToOneDescriptor, ForwardManyToOneDescriptor
from django.db.utils import DEFAULT_DB_ALIAS
from django.utils import six
@@ -178,14 +179,6 @@ class PolymorphicModel(six.with_metaclass(PolymorphicModelBase, models.Model)):
subclasses_and_superclasses_accessors = self._get_inheritance_relation_fields_and_models()
- try:
- from django.db.models.fields.related import ReverseOneToOneDescriptor, ForwardManyToOneDescriptor
- except ImportError:
- # django < 1.9
- from django.db.models.fields.related import (
- SingleRelatedObjectDescriptor as ReverseOneToOneDescriptor,
- ReverseSingleRelatedObjectDescriptor as ForwardManyToOneDescriptor,
- )
for name, model in subclasses_and_superclasses_accessors.items():
# Here be dragons.
orig_accessor = getattr(self.__class__, name, None)
diff --git a/polymorphic/tests/admintestcase.py b/polymorphic/tests/admintestcase.py
index fb2e560..618d8fc 100644
--- a/polymorphic/tests/admintestcase.py
+++ b/polymorphic/tests/admintestcase.py
@@ -49,7 +49,7 @@ class AdminTestCase(TestCase):
# Make sure the URLs are reachable by reverse()
clear_url_caches()
set_urlconf(tuple([
- url('^tmp-admin/', include(self.admin_site.urls))
+ url('^tmp-admin/', self.admin_site.urls)
]))
def get_admin_instance(self, model):
diff --git a/polymorphic/tests/models.py b/polymorphic/tests/models.py
index 47f21e4..60fc619 100644
--- a/polymorphic/tests/models.py
+++ b/polymorphic/tests/models.py
@@ -237,21 +237,6 @@ class PlainChildModelWithManager(models.Model):
objects = PlainMyManager()
-class MgrInheritA(models.Model):
- mgrA = models.Manager()
- mgrA2 = models.Manager()
- field1 = models.CharField(max_length=10)
-
-
-class MgrInheritB(MgrInheritA):
- mgrB = models.Manager()
- field2 = models.CharField(max_length=10)
-
-
-class MgrInheritC(ShowFieldTypeAndContent, MgrInheritB):
- pass
-
-
class BlogBase(ShowFieldTypeAndContent, PolymorphicModel):
name = models.CharField(max_length=10)
diff --git a/polymorphic/tests/test_orm.py b/polymorphic/tests/test_orm.py
index 441877e..335d450 100644
--- a/polymorphic/tests/test_orm.py
+++ b/polymorphic/tests/test_orm.py
@@ -228,14 +228,14 @@ class PolymorphicTests(TransactionTestCase):
objects_deferred = Model2A.objects.defer('field1')
self.assertNotIn('field1', objects_deferred[0].__dict__, 'field1 was not deferred (using defer())')
- self.assertEqual(repr(objects_deferred[0]),
- '')
- self.assertEqual(repr(objects_deferred[1]),
- '')
- self.assertEqual(repr(objects_deferred[2]),
- '')
- self.assertEqual(repr(objects_deferred[3]),
- '')
+ self.assertRegex(repr(objects_deferred[0]),
+ '')
+ self.assertRegex(repr(objects_deferred[1]),
+ '')
+ self.assertRegex(repr(objects_deferred[2]),
+ '')
+ self.assertRegex(repr(objects_deferred[3]),
+ '')
objects_only = Model2A.objects.only('pk', 'polymorphic_ctype', 'field1')
@@ -246,33 +246,33 @@ class PolymorphicTests(TransactionTestCase):
' on a child model')
self.assertNotIn('field4', objects_only[3].__dict__,
'field4 was not deferred (using only())')
- self.assertEqual(repr(objects_only[0]),
- '')
- self.assertEqual(repr(objects_only[1]),
- '')
- self.assertEqual(repr(objects_only[2]),
- '')
- self.assertEqual(repr(objects_only[3]),
- '')
+ self.assertRegex(repr(objects_only[0]),
+ '')
+ self.assertRegex(repr(objects_only[1]),
+ '')
+ self.assertRegex(repr(objects_only[2]),
+ '')
+ self.assertRegex(repr(objects_only[3]),
+ '')
ModelX.objects.create(field_b="A1", field_x="A2")
ModelY.objects.create(field_b="B1", field_y="B2")
objects_deferred = Base.objects.defer('ModelY___field_y')
- self.assertEqual(repr(objects_deferred[0]),
- '')
- self.assertEqual(repr(objects_deferred[1]),
- '')
+ self.assertRegex(repr(objects_deferred[0]),
+ '')
+ self.assertRegex(repr(objects_deferred[1]),
+ '')
objects_only = Base.objects.only(
'polymorphic_ctype', 'ModelY___field_y', 'ModelX___field_x',
)
- self.assertEqual(repr(objects_only[0]),
- '')
- self.assertEqual(repr(objects_only[1]),
- '')
+ self.assertRegex(repr(objects_only[0]),
+ '')
+ self.assertRegex(repr(objects_only[1]),
+ '')
def test_defer_related_fields(self):
self.create_model2abcd()
@@ -997,17 +997,3 @@ class PolymorphicTests(TransactionTestCase):
MultiTableDerived.objects.bulk_create([
MultiTableDerived(field1='field1', field2='field2')
])
-
-
-def qrepr(data):
- """
- Ensure consistent repr() output for the QuerySet object.
- """
- if isinstance(data, QuerySet):
- if django.VERSION < (1, 11):
- # Django 1.10 still shows "= 1.10
+ Django >= 1.11
[options.packages.find]
exclude =
diff --git a/tox.ini b/tox.ini
index f8e95a8..6c96640 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,9 +1,9 @@
[tox]
envlist =
- py27-django{110,111}
- py34-django{110,111}
- py35-django{110,111,master}
- py36-django{111,master}
+ py27-django{111}
+ py34-django{111,200}
+ py35-django{111,200,master}
+ py36-django{111,200,master}
docs
[testenv]
@@ -14,8 +14,8 @@ setenv =
deps =
coverage
dj-database-url
- django110: Django >= 1.10, < 1.11
django111: Django >= 1.11, < 2.0
+ django200: Django ~= 2.0.0
djangomaster: https://github.com/django/django/archive/master.tar.gz
postgres: psycopg2
commands =