Drop support for Django 1.8

fix_request_path_info
Jerome Leclanche 2017-05-19 09:58:34 +03:00
parent f9b079fda7
commit 0c7b1aa657
8 changed files with 38 additions and 271 deletions

View File

@ -3,12 +3,7 @@ Rendering utils for admin forms;
This makes sure that admin fieldsets/layout settings are exported to the template.
"""
import json
from django.contrib.admin.helpers import InlineAdminFormSet, InlineAdminForm, AdminField
from django.utils.encoding import force_text
from django.utils.text import capfirst
from django.utils.translation import ugettext
from polymorphic.formsets import BasePolymorphicModelFormSet
@ -82,30 +77,6 @@ class PolymorphicInlineAdminFormSet(InlineAdminFormSet):
fields.update(child_inline.get_prepopulated_fields(self.request, self.obj))
return fields
# The polymorphic template follows the same method like all other inlines do in Django 1.10.
# This method is added for compatibility with older Django versions.
def inline_formset_data(self):
"""
A JavaScript data structure for the JavaScript code
"""
verbose_name = self.opts.verbose_name
return json.dumps({
'name': '#%s' % self.formset.prefix,
'options': {
'prefix': self.formset.prefix,
'addText': ugettext('Add another %(verbose_name)s') % {
'verbose_name': capfirst(verbose_name),
},
'childTypes': [
{
'type': model._meta.model_name,
'name': force_text(model._meta.verbose_name)
} for model in self.formset.child_forms.keys()
],
'deleteText': ugettext('Remove'),
}
})
class PolymorphicInlineSupportMixin(object):
"""

View File

@ -4,7 +4,6 @@ The parent admin displays the list view of the base model.
import sys
import warnings
import django
from django.conf.urls import url
from django.contrib import admin
from django.contrib.admin.helpers import AdminErrorList, AdminForm
@ -270,31 +269,10 @@ class PolymorphicParentModelAdmin(admin.ModelAdmin):
if not self._compat_mode:
return urls
info = _get_opt(self.model)
# Patch the change view URL so it's not a big catch-all; allowing all
# custom URLs to be added to the end. This is done by adding '/$' to the
# end of the regex. The url needs to be recreated, patching url.regex
# is not an option Django 1.4's LocaleRegexProvider changed it.
if django.VERSION < (1, 9):
# On Django 1.9, the change view URL has been changed from
# /<app>/<model>/<pk>/ to /<app>/<model>/<pk>/change/, which is
# why we can skip this workaround for Django >= 1.9.
new_change_url = url(
r'^{0}/$'.format(self.pk_regex),
self.admin_site.admin_view(self.change_view),
name='{0}_{1}_change'.format(*info)
)
redirect_urls = []
for i, oldurl in enumerate(urls):
if oldurl.name == new_change_url.name:
urls[i] = new_change_url
else:
# For Django 1.9, the redirect at the end acts as catch all.
# The custom urls need to be inserted before that.
redirect_urls = [pat for pat in urls if not pat.name] # redirect URL has no name.
urls = [pat for pat in urls if pat.name]
# The redirect at the end acts as catch all.
# The custom urls need to be inserted before that.
redirect_urls = [pat for pat in urls if not pat.name] # redirect URL has no name.
urls = [pat for pat in urls if pat.name]
# Define the catch-all for custom views
custom_urls = [
@ -421,7 +399,3 @@ class PolymorphicParentModelAdmin(admin.ModelAdmin):
"admin/%s/change_list.html" % base_app_label,
"admin/change_list.html"
]
def _get_opt(model):
return model._meta.app_label, model._meta.model_name

View File

@ -4,11 +4,10 @@ PolymorphicModel Meta Class
"""
from __future__ import absolute_import
import inspect
import os
import sys
import inspect
import django
from django.db import models
from django.db.models.base import ModelBase
from django.db.models.manager import ManagerDescriptor
@ -22,11 +21,6 @@ POLYMORPHIC_SPECIAL_Q_KWORDS = ['instance_of', 'not_instance_of']
DUMPDATA_COMMAND = os.path.join('django', 'core', 'management', 'commands', 'dumpdata.py')
try:
from django.db.models.manager import AbstractManagerDescriptor # Django 1.5
except ImportError:
AbstractManagerDescriptor = None
###################################################################################
# PolymorphicModel meta class
@ -60,11 +54,6 @@ class PolymorphicModelBase(ModelBase):
# Workaround compatibility issue with six.with_metaclass() and custom Django model metaclasses:
if not attrs and model_name == 'NewBase':
if django.VERSION < (1, 5):
# Let Django fully ignore the class which is inserted in between.
# Django 1.5 fixed this, see https://code.djangoproject.com/ticket/19688
attrs['__module__'] = 'django.utils.six'
attrs['Meta'] = type('Meta', (), {'abstract': True})
return super(PolymorphicModelBase, self).__new__(self, model_name, bases, attrs)
# create new model
@ -73,33 +62,9 @@ class PolymorphicModelBase(ModelBase):
# check if the model fields are all allowed
self.validate_model_fields(new_class)
# create list of all managers to be inherited from the base classes
if django.VERSION < (1, 10):
inherited_managers = new_class.get_inherited_managers(attrs)
# add the managers to the new model
for source_name, mgr_name, manager in inherited_managers:
# print '** add inherited manager from model %s, manager %s, %s' % (source_name, mgr_name, manager.__class__.__name__)
new_manager = manager._copy_to_model(new_class)
if mgr_name == '_default_manager':
new_class._default_manager = new_manager
else:
new_class.add_to_class(mgr_name, new_manager)
# get first user defined manager; if there is one, make it the _default_manager
# this value is used by the related objects, restoring access to custom queryset methods on related objects.
user_manager = self.get_first_user_defined_manager(new_class)
if user_manager:
# print '## add default manager', type(def_mgr)
new_class._default_manager = user_manager._copy_to_model(new_class)
new_class._default_manager._inherited = False # the default mgr was defined by the user, not inherited
# validate resulting default manager (only on non-abstract and non-swapped models)
# validate resulting default manager
if not new_class._meta.abstract and not new_class._meta.swapped:
if django.VERSION >= (1, 10):
self.validate_model_manager(new_class.objects, model_name, 'objects')
else:
self.validate_model_manager(new_class._default_manager, model_name, '_default_manager')
self.validate_model_manager(new_class.objects, model_name, "objects")
# for __init__ function of this class (monkeypatching inheritance accessors)
new_class.polymorphic_super_sub_accessors_replaced = False
@ -113,73 +78,6 @@ class PolymorphicModelBase(ModelBase):
return new_class
if django.VERSION < (1, 10):
def get_inherited_managers(self, attrs):
"""
Return list of all managers to be inherited/propagated from the base classes;
use correct mro, only use managers with _inherited==False (they are of no use),
skip managers that are overwritten by the user with same-named class attributes (in attrs)
"""
# print "** ", self.__name__
add_managers = []
add_managers_keys = set()
for base in self.__mro__[1:]:
if not issubclass(base, models.Model):
continue
if not getattr(base, 'polymorphic_model_marker', None):
continue # leave managers of non-polym. models alone
for key, manager in base.__dict__.items():
if type(manager) == models.manager.ManagerDescriptor:
manager = manager.manager
# As of Django 1.5, the abstract models don't get any managers, only a
# AbstractManagerDescriptor as substitute.
if type(manager) == AbstractManagerDescriptor and base.__name__ == 'PolymorphicModel':
model = manager.model
if key == 'objects':
manager = PolymorphicManager()
manager.model = model
elif key == 'base_objects':
manager = models.Manager()
manager.model = model
if AbstractManagerDescriptor is not None:
# Django 1.4 unconditionally assigned managers to a model. As of Django 1.5 however,
# the abstract models don't get any managers, only a AbstractManagerDescriptor as substitute.
# Pretend that the manager is still there, so all code works like it used to.
if type(manager) == AbstractManagerDescriptor and base.__name__ == 'PolymorphicModel':
model = manager.model
if key == 'objects':
manager = PolymorphicManager()
manager.model = model
elif key == 'base_objects':
manager = models.Manager()
manager.model = model
if not isinstance(manager, models.Manager):
continue
if key == '_base_manager':
continue # let Django handle _base_manager
if key in attrs:
continue
if key in add_managers_keys:
continue # manager with that name already added, skip
if manager._inherited:
continue # inherited managers (on the bases) have no significance, they are just copies
# print '## {0} {1}'.format(self.__name__, key)
if isinstance(manager, PolymorphicManager): # validate any inherited polymorphic managers
self.validate_model_manager(manager, self.__name__, key)
add_managers.append((base.__name__, key, manager))
add_managers_keys.add(key)
# The ordering in the base.__dict__ may randomly change depending on which method is added.
# Make sure base_objects is on top, and 'objects' and '_default_manager' follow afterwards.
# This makes sure that the _base_manager is also assigned properly.
add_managers = sorted(add_managers, key=lambda item: (item[1].startswith('_'), item[1]))
return add_managers
@classmethod
def get_first_user_defined_manager(mcs, new_class):
# See if there is a manager attribute directly stored at this inheritance level.

View File

@ -1,4 +1,3 @@
import django
from django.contrib.contenttypes.forms import BaseGenericInlineFormSet, generic_inlineformset_factory
from django.contrib.contenttypes.models import ContentType
from django.db import models
@ -32,12 +31,8 @@ class GenericPolymorphicFormSetChild(PolymorphicFormSetChild):
opts = self.model._meta
ct_field = opts.get_field(self.ct_field)
if django.VERSION >= (1, 9):
if not isinstance(ct_field, models.ForeignKey) or ct_field.remote_field.model != ContentType:
raise Exception("fk_name '%s' is not a ForeignKey to ContentType" % ct_field)
else:
if not isinstance(ct_field, models.ForeignKey) or ct_field.rel.to != ContentType:
raise Exception("fk_name '%s' is not a ForeignKey to ContentType" % ct_field)
if not isinstance(ct_field, models.ForeignKey) or ct_field.remote_field.model != ContentType:
raise Exception("fk_name '%s' is not a ForeignKey to ContentType" % ct_field)
fk_field = opts.get_field(self.fk_field) # let the exception propagate
exclude.extend([ct_field.name, fk_field.name])

View File

@ -1,6 +1,5 @@
from collections import OrderedDict
import django
from django import forms
from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ImproperlyConfigured, ValidationError
@ -226,10 +225,7 @@ class BasePolymorphicModelFormSet(BaseModelFormSet):
"""
forms = []
for model, form_class in self.child_forms.items():
if django.VERSION >= (1, 9):
kwargs = self.get_form_kwargs(None) # New Django 1.9 method
else:
kwargs = {}
kwargs = self.get_form_kwargs(None)
form = form_class(
auto_id=self.auto_id,

View File

@ -7,9 +7,8 @@ from __future__ import absolute_import
import copy
from collections import defaultdict
import django
from django.contrib.contenttypes.models import ContentType
from django.db.models.query import Q, QuerySet
from django.db.models.query import ModelIterable, Q, QuerySet
from django.utils import six
from .query_translate import translate_polymorphic_filter_definitions_in_kwargs, translate_polymorphic_filter_definitions_in_args
@ -54,23 +53,19 @@ def _polymorphic_iterator(queryset, base_iter):
return
if django.VERSION >= (1, 9):
# We ignore this on django < 1.9, as ModelIterable didn't yet exist.
from django.db.models.query import ModelIterable
class PolymorphicModelIterable(ModelIterable):
"""
ModelIterable for PolymorphicModel
class PolymorphicModelIterable(ModelIterable):
"""
ModelIterable for PolymorphicModel
Yields real instances if qs.polymorphic_disabled is False,
otherwise acts like a regular ModelIterable.
"""
Yields real instances if qs.polymorphic_disabled is False,
otherwise acts like a regular ModelIterable.
"""
def __iter__(self):
base_iter = super(PolymorphicModelIterable, self).__iter__()
if self.queryset.polymorphic_disabled:
return base_iter
return _polymorphic_iterator(self.queryset, base_iter)
def __iter__(self):
base_iter = super(PolymorphicModelIterable, self).__iter__()
if self.queryset.polymorphic_disabled:
return base_iter
return _polymorphic_iterator(self.queryset, base_iter)
def transmogrify(cls, obj):
@ -104,9 +99,7 @@ class PolymorphicQuerySet(QuerySet):
def __init__(self, *args, **kwargs):
super(PolymorphicQuerySet, self).__init__(*args, **kwargs)
if django.VERSION >= (1, 9):
# On django < 1.9 we override the iterator() method instead
self._iterable_class = PolymorphicModelIterable
self._iterable_class = PolymorphicModelIterable
self.polymorphic_disabled = False
# A parallel structure to django.db.models.query.Query.deferred_loading,
@ -282,16 +275,13 @@ class PolymorphicQuerySet(QuerySet):
qs = self.non_polymorphic()
return super(PolymorphicQuerySet, qs).aggregate(*args, **kwargs)
if django.VERSION >= (1, 9):
# On Django < 1.9, 'qs.values(...)' returned a new special ValuesQuerySet
# object, which our polymorphic modifications didn't apply to.
# Starting with Django 1.9, the copy returned by 'qs.values(...)' has the
# same class as 'qs', so our polymorphic modifications would apply.
# We want to leave values queries untouched, so we set 'polymorphic_disabled'.
def _values(self, *args, **kwargs):
clone = super(PolymorphicQuerySet, self)._values(*args, **kwargs)
clone.polymorphic_disabled = True
return clone
# Starting with Django 1.9, the copy returned by 'qs.values(...)' has the
# same class as 'qs', so our polymorphic modifications would apply.
# We want to leave values queries untouched, so we set 'polymorphic_disabled'.
def _values(self, *args, **kwargs):
clone = super(PolymorphicQuerySet, self)._values(*args, **kwargs)
clone.polymorphic_disabled = True
return clone
# Since django_polymorphic 'V1.0 beta2', extra() always returns polymorphic results.
# The resulting objects are required to have a unique primary key within the result set
@ -445,34 +435,6 @@ class PolymorphicQuerySet(QuerySet):
return resultlist
if django.VERSION < (1, 9):
# On django 1.9+, we can define self._iterator_class instead of iterator()
def iterator(self):
"""
This function is used by Django 1.8 and earlier for all object retrieval.
By overriding it, we modify the objects that this queryset returns
when it is evaluated (or its get method or other object-returning methods are called).
Here we do the same as::
base_result_objects = list(super(PolymorphicQuerySet, self).iterator())
real_results = self._get_real_instances(base_result_objects)
for o in real_results: yield o
but it requests the objects in chunks from the database,
with Polymorphic_QuerySet_objects_per_request per chunk
"""
base_iter = super(PolymorphicQuerySet, self).iterator()
# disabled => work just like a normal queryset
if self.polymorphic_disabled:
for o in base_iter:
yield o
return
for o in _polymorphic_iterator(self, base_iter):
yield o
def __repr__(self, *args, **kwargs):
if self.model.polymorphic_query_multiline_output:
result = [repr(o) for o in self.all()]

View File

@ -5,8 +5,8 @@ PolymorphicQuerySet support functions
from __future__ import absolute_import
import copy
import django
from functools import reduce
from django.contrib.contenttypes.models import ContentType
from django.db import models
from django.db.models.fields.related import ForeignObjectRel, RelatedField
@ -86,13 +86,7 @@ def translate_polymorphic_filter_definitions_in_args(queryset_model, args, using
Returns: modified Q objects
"""
if django.VERSION >= (1, 10):
q_objects = [copy.deepcopy(q) for q in args]
elif django.VERSION >= (1, 8):
q_objects = [q.clone() for q in args]
else:
q_objects = args # NOTE: edits existing objects in place.
return [translate_polymorphic_Q_object(queryset_model, q, using=using) for q in q_objects]
return [translate_polymorphic_Q_object(queryset_model, copy.deepcopy(q), using=using) for q in args]
def _translate_polymorphic_filter_definition(queryset_model, field_path, field_val, using=DEFAULT_DB_ALIAS):

View File

@ -260,20 +260,11 @@ class PolymorphicTests(TestCase):
self.assertEqual(show_base_manager(PlainC), "<class 'django.db.models.manager.Manager'> <class 'polymorphic.tests.PlainC'>")
self.assertEqual(show_base_manager(Model2A), "<class 'polymorphic.managers.PolymorphicManager'> <class 'polymorphic.tests.Model2A'>")
if django.VERSION >= (1, 10):
# The new inheritance makes all model levels polymorphic
self.assertEqual(show_base_manager(Model2B), "<class 'polymorphic.managers.PolymorphicManager'> <class 'polymorphic.tests.Model2B'>")
self.assertEqual(show_base_manager(Model2C), "<class 'polymorphic.managers.PolymorphicManager'> <class 'polymorphic.tests.Model2C'>")
else:
self.assertEqual(show_base_manager(Model2B), "<class 'django.db.models.manager.Manager'> <class 'polymorphic.tests.Model2B'>")
self.assertEqual(show_base_manager(Model2C), "<class 'django.db.models.manager.Manager'> <class 'polymorphic.tests.Model2C'>")
self.assertEqual(show_base_manager(Model2B), "<class 'polymorphic.managers.PolymorphicManager'> <class 'polymorphic.tests.Model2B'>")
self.assertEqual(show_base_manager(Model2C), "<class 'polymorphic.managers.PolymorphicManager'> <class 'polymorphic.tests.Model2C'>")
self.assertEqual(show_base_manager(One2OneRelatingModel), "<class 'polymorphic.managers.PolymorphicManager'> <class 'polymorphic.tests.One2OneRelatingModel'>")
if django.VERSION >= (1, 10):
# The new inheritance makes all model levels polymorphic
self.assertEqual(show_base_manager(One2OneRelatingModelDerived), "<class 'polymorphic.managers.PolymorphicManager'> <class 'polymorphic.tests.One2OneRelatingModelDerived'>")
else:
self.assertEqual(show_base_manager(One2OneRelatingModelDerived), "<class 'django.db.models.manager.Manager'> <class 'polymorphic.tests.One2OneRelatingModelDerived'>")
self.assertEqual(show_base_manager(One2OneRelatingModelDerived), "<class 'polymorphic.managers.PolymorphicManager'> <class 'polymorphic.tests.One2OneRelatingModelDerived'>")
def test_instance_default_manager(self):
def show_default_manager(instance):
@ -566,17 +557,6 @@ class PolymorphicTests(TestCase):
# by choice of MRO, should be MyManager from MROBase1.
self.assertIs(type(MRODerived.objects), MyManager)
if django.VERSION < (1, 10, 1):
# The change for https://code.djangoproject.com/ticket/27073
# in https://github.com/django/django/commit/d4eefc7e2af0d93283ed1c03e0af0a482982b6f0
# removes the assignment to _default_manager
# check for correct default manager
self.assertIs(type(MROBase1._default_manager), MyManager)
# Django vanilla inheritance does not inherit MyManager as _default_manager here
self.assertIs(type(MROBase2._default_manager), MyManager)
def test_queryset_assignment(self):
# This is just a consistency check for now, testing standard Django behavior.
parent = PlainParentModelWithManager.objects.create()
@ -783,13 +763,10 @@ def qrepr(data):
Ensure consistent repr() output for the QuerySet object.
"""
if isinstance(data, QuerySet):
if django.VERSION >= (1, 11):
return repr(data)
elif django.VERSION >= (1, 10):
# Django 1.11 still shows "<QuerySet [", not taking the actual type into account.
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:
# Simulate Django 1.11 behavior for older Django versions.
return '<{0} {1}>'.format(data.__class__.__name__, repr(data))
return repr(data)
return repr(data)