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. 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.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 from polymorphic.formsets import BasePolymorphicModelFormSet
@ -82,30 +77,6 @@ class PolymorphicInlineAdminFormSet(InlineAdminFormSet):
fields.update(child_inline.get_prepopulated_fields(self.request, self.obj)) fields.update(child_inline.get_prepopulated_fields(self.request, self.obj))
return fields 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): class PolymorphicInlineSupportMixin(object):
""" """

View File

@ -4,7 +4,6 @@ The parent admin displays the list view of the base model.
import sys import sys
import warnings import warnings
import django
from django.conf.urls import url from django.conf.urls import url
from django.contrib import admin from django.contrib import admin
from django.contrib.admin.helpers import AdminErrorList, AdminForm from django.contrib.admin.helpers import AdminErrorList, AdminForm
@ -270,28 +269,7 @@ class PolymorphicParentModelAdmin(admin.ModelAdmin):
if not self._compat_mode: if not self._compat_mode:
return urls return urls
info = _get_opt(self.model) # The redirect at the end acts as catch all.
# 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. # 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. 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] urls = [pat for pat in urls if pat.name]
@ -421,7 +399,3 @@ class PolymorphicParentModelAdmin(admin.ModelAdmin):
"admin/%s/change_list.html" % base_app_label, "admin/%s/change_list.html" % base_app_label,
"admin/change_list.html" "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 from __future__ import absolute_import
import inspect
import os import os
import sys import sys
import inspect
import django
from django.db import models from django.db import models
from django.db.models.base import ModelBase from django.db.models.base import ModelBase
from django.db.models.manager import ManagerDescriptor 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') 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 # PolymorphicModel meta class
@ -60,11 +54,6 @@ class PolymorphicModelBase(ModelBase):
# Workaround compatibility issue with six.with_metaclass() and custom Django model metaclasses: # Workaround compatibility issue with six.with_metaclass() and custom Django model metaclasses:
if not attrs and model_name == 'NewBase': 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) return super(PolymorphicModelBase, self).__new__(self, model_name, bases, attrs)
# create new model # create new model
@ -73,33 +62,9 @@ class PolymorphicModelBase(ModelBase):
# check if the model fields are all allowed # check if the model fields are all allowed
self.validate_model_fields(new_class) self.validate_model_fields(new_class)
# create list of all managers to be inherited from the base classes # validate resulting default manager
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)
if not new_class._meta.abstract and not new_class._meta.swapped: 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")
self.validate_model_manager(new_class.objects, model_name, 'objects')
else:
self.validate_model_manager(new_class._default_manager, model_name, '_default_manager')
# for __init__ function of this class (monkeypatching inheritance accessors) # for __init__ function of this class (monkeypatching inheritance accessors)
new_class.polymorphic_super_sub_accessors_replaced = False new_class.polymorphic_super_sub_accessors_replaced = False
@ -113,73 +78,6 @@ class PolymorphicModelBase(ModelBase):
return new_class 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 @classmethod
def get_first_user_defined_manager(mcs, new_class): def get_first_user_defined_manager(mcs, new_class):
# See if there is a manager attribute directly stored at this inheritance level. # 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.forms import BaseGenericInlineFormSet, generic_inlineformset_factory
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.db import models from django.db import models
@ -32,12 +31,8 @@ class GenericPolymorphicFormSetChild(PolymorphicFormSetChild):
opts = self.model._meta opts = self.model._meta
ct_field = opts.get_field(self.ct_field) 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: 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) 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)
fk_field = opts.get_field(self.fk_field) # let the exception propagate fk_field = opts.get_field(self.fk_field) # let the exception propagate
exclude.extend([ct_field.name, fk_field.name]) exclude.extend([ct_field.name, fk_field.name])

View File

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

View File

@ -7,9 +7,8 @@ from __future__ import absolute_import
import copy import copy
from collections import defaultdict from collections import defaultdict
import django
from django.contrib.contenttypes.models import ContentType 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 django.utils import six
from .query_translate import translate_polymorphic_filter_definitions_in_kwargs, translate_polymorphic_filter_definitions_in_args from .query_translate import translate_polymorphic_filter_definitions_in_kwargs, translate_polymorphic_filter_definitions_in_args
@ -54,11 +53,7 @@ def _polymorphic_iterator(queryset, base_iter):
return return
if django.VERSION >= (1, 9): class PolymorphicModelIterable(ModelIterable):
# 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 ModelIterable for PolymorphicModel
@ -104,8 +99,6 @@ class PolymorphicQuerySet(QuerySet):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(PolymorphicQuerySet, self).__init__(*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 self.polymorphic_disabled = False
@ -282,9 +275,6 @@ class PolymorphicQuerySet(QuerySet):
qs = self.non_polymorphic() qs = self.non_polymorphic()
return super(PolymorphicQuerySet, qs).aggregate(*args, **kwargs) 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 # Starting with Django 1.9, the copy returned by 'qs.values(...)' has the
# same class as 'qs', so our polymorphic modifications would apply. # same class as 'qs', so our polymorphic modifications would apply.
# We want to leave values queries untouched, so we set 'polymorphic_disabled'. # We want to leave values queries untouched, so we set 'polymorphic_disabled'.
@ -445,34 +435,6 @@ class PolymorphicQuerySet(QuerySet):
return resultlist 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): def __repr__(self, *args, **kwargs):
if self.model.polymorphic_query_multiline_output: if self.model.polymorphic_query_multiline_output:
result = [repr(o) for o in self.all()] result = [repr(o) for o in self.all()]

View File

@ -5,8 +5,8 @@ PolymorphicQuerySet support functions
from __future__ import absolute_import from __future__ import absolute_import
import copy import copy
import django
from functools import reduce from functools import reduce
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.db import models from django.db import models
from django.db.models.fields.related import ForeignObjectRel, RelatedField 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 Returns: modified Q objects
""" """
if django.VERSION >= (1, 10): return [translate_polymorphic_Q_object(queryset_model, copy.deepcopy(q), using=using) for q in args]
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]
def _translate_polymorphic_filter_definition(queryset_model, field_path, field_val, using=DEFAULT_DB_ALIAS): 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(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'>") 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(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(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(One2OneRelatingModel), "<class 'polymorphic.managers.PolymorphicManager'> <class 'polymorphic.tests.One2OneRelatingModel'>") 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'>") 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'>")
def test_instance_default_manager(self): def test_instance_default_manager(self):
def show_default_manager(instance): def show_default_manager(instance):
@ -566,17 +557,6 @@ class PolymorphicTests(TestCase):
# by choice of MRO, should be MyManager from MROBase1. # by choice of MRO, should be MyManager from MROBase1.
self.assertIs(type(MRODerived.objects), MyManager) 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): def test_queryset_assignment(self):
# This is just a consistency check for now, testing standard Django behavior. # This is just a consistency check for now, testing standard Django behavior.
parent = PlainParentModelWithManager.objects.create() parent = PlainParentModelWithManager.objects.create()
@ -783,13 +763,10 @@ def qrepr(data):
Ensure consistent repr() output for the QuerySet object. Ensure consistent repr() output for the QuerySet object.
""" """
if isinstance(data, QuerySet): if isinstance(data, QuerySet):
if django.VERSION >= (1, 11): if django.VERSION < (1, 11):
return repr(data) # Django 1.10 still shows "<QuerySet [", not taking the actual type into account.
elif django.VERSION >= (1, 10):
# Django 1.11 still shows "<QuerySet [", not taking the actual type into account.
return '<{0} {1}'.format(data.__class__.__name__, repr(data)[10:]) return '<{0} {1}'.format(data.__class__.__name__, repr(data)[10:])
else: else:
# Simulate Django 1.11 behavior for older Django versions. return repr(data)
return '<{0} {1}>'.format(data.__class__.__name__, repr(data))
return repr(data) return repr(data)