Merge pull request #318 from meshy/django-2.0

Add django 2.0 support
fix_request_path_info
Diederik van der Boor 2018-01-18 15:43:59 +01:00 committed by GitHub
commit e164026b43
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 69 additions and 87 deletions

View File

@ -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:

View File

@ -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 <https://django-polymorphic.readthedocs.io/>`_.

View File

@ -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.

View File

@ -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
------------------------------

View File

@ -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))

View File

@ -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)

View File

@ -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)

View File

@ -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):

View File

@ -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)

View File

@ -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]),
'<Model2A: id 1, field1 (CharField), deferred[field1]>')
self.assertEqual(repr(objects_deferred[1]),
'<Model2B: id 2, field1 (CharField), field2 (CharField), deferred[field1]>')
self.assertEqual(repr(objects_deferred[2]),
'<Model2C: id 3, field1 (CharField), field2 (CharField), field3 (CharField), deferred[field1]>')
self.assertEqual(repr(objects_deferred[3]),
'<Model2D: id 4, field1 (CharField), field2 (CharField), field3 (CharField), field4 (CharField), deferred[field1]>')
self.assertRegex(repr(objects_deferred[0]),
'<Model2A: id \d+, field1 \(CharField\), deferred\[field1\]>')
self.assertRegex(repr(objects_deferred[1]),
'<Model2B: id \d+, field1 \(CharField\), field2 \(CharField\), deferred\[field1\]>')
self.assertRegex(repr(objects_deferred[2]),
'<Model2C: id \d+, field1 \(CharField\), field2 \(CharField\), field3 \(CharField\), deferred\[field1\]>')
self.assertRegex(repr(objects_deferred[3]),
'<Model2D: id \d+, field1 \(CharField\), field2 \(CharField\), field3 \(CharField\), field4 \(CharField\), deferred\[field1\]>')
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]),
'<Model2A: id 1, field1 (CharField)>')
self.assertEqual(repr(objects_only[1]),
'<Model2B: id 2, field1 (CharField), field2 (CharField), deferred[field2]>')
self.assertEqual(repr(objects_only[2]),
'<Model2C: id 3, field1 (CharField), field2 (CharField), field3 (CharField), '
'deferred[field2,field3,model2a_ptr_id]>')
self.assertEqual(repr(objects_only[3]),
'<Model2D: id 4, field1 (CharField), field2 (CharField), field3 (CharField), field4 (CharField), '
'deferred[field2,field3,field4,model2a_ptr_id,model2b_ptr_id]>')
self.assertRegex(repr(objects_only[0]),
'<Model2A: id \d+, field1 \(CharField\)>')
self.assertRegex(repr(objects_only[1]),
'<Model2B: id \d+, field1 \(CharField\), field2 \(CharField\), deferred\[field2\]>')
self.assertRegex(repr(objects_only[2]),
'<Model2C: id \d+, field1 \(CharField\), field2 \(CharField\), field3 \(CharField\), '
'deferred\[field2,field3,model2a_ptr_id\]>')
self.assertRegex(repr(objects_only[3]),
'<Model2D: id \d+, field1 \(CharField\), field2 \(CharField\), field3 \(CharField\), field4 \(CharField\), '
'deferred\[field2,field3,field4,model2a_ptr_id,model2b_ptr_id\]>')
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]),
'<ModelX: id 3, field_b (CharField), field_x (CharField)>')
self.assertEqual(repr(objects_deferred[1]),
'<ModelY: id 4, field_b (CharField), field_y (CharField), deferred[field_y]>')
self.assertRegex(repr(objects_deferred[0]),
'<ModelX: id \d+, field_b \(CharField\), field_x \(CharField\)>')
self.assertRegex(repr(objects_deferred[1]),
'<ModelY: id \d+, field_b \(CharField\), field_y \(CharField\), deferred\[field_y\]>')
objects_only = Base.objects.only(
'polymorphic_ctype', 'ModelY___field_y', 'ModelX___field_x',
)
self.assertEqual(repr(objects_only[0]),
'<ModelX: id 3, field_b (CharField), field_x (CharField), deferred[field_b]>')
self.assertEqual(repr(objects_only[1]),
'<ModelY: id 4, field_b (CharField), field_y (CharField), deferred[field_b]>')
self.assertRegex(repr(objects_only[0]),
'<ModelX: id \d+, field_b \(CharField\), field_x \(CharField\), deferred\[field_b\]>')
self.assertRegex(repr(objects_only[1]),
'<ModelY: id \d+, field_b \(CharField\), field_y \(CharField\), deferred\[field_b\]>')
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 "<QuerySet [", not taking the actual type into account.
return '<{0} {1}'.format(data.__class__.__name__, repr(data)[10:])
else:
return repr(data)
return repr(data)

View File

@ -14,8 +14,8 @@ classifiers =
Development Status :: 5 - Production/Stable
Environment :: Web Environment
Framework :: Django
Framework :: Django :: 1.10
Framework :: Django :: 1.11
Framework :: Django :: 2.0
Intended Audience :: Developers
License :: OSI Approved :: BSD License
Operating System :: OS Independent
@ -30,7 +30,7 @@ classifiers =
packages = find:
include_package_data = True
install_requires =
Django >= 1.10
Django >= 1.11
[options.packages.find]
exclude =

10
tox.ini
View File

@ -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 =