cleanup: remove code for old djago

This commit is contained in:
Sergey Tereschenko 2019-02-16 15:12:53 +02:00
parent 63543f2356
commit 84115df1dc

View file

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
from functools import partial
from django import VERSION
import django
from django.utils.six import with_metaclass
from django.core.exceptions import ImproperlyConfigured
from django.db.models import Manager, ForeignKey, OneToOneField
@ -17,10 +17,6 @@ from modeltranslation.manager import (MultilingualManager, MultilingualQuerysetM
from modeltranslation.utils import build_localized_fieldname, parse_field
NEW_RELATED_API = VERSION >= (1, 9)
NEW_DEFERRED_API = NEW_MANAGER_API = NEW_ABSTRACT_API = VERSION >= (1, 10)
class AlreadyRegistered(Exception):
pass
@ -163,12 +159,8 @@ def add_translation_fields(model, opts):
# Rebuild information about parents fields. If there are opts.local_fields, field cache would be
# invalidated (by model._meta.add_field() function). Otherwise, we need to do it manually.
if len(opts.local_fields) == 0:
try:
model._meta._fill_fields_cache()
except AttributeError:
# Django 1.8 removed _fill_fields_cache
model._meta._expire_cache()
model._meta.get_fields()
model._meta._expire_cache()
model._meta.get_fields()
def has_custom_queryset(manager):
@ -178,6 +170,29 @@ def has_custom_queryset(manager):
return old_diff or new_diff
def patch_manager_class(manager):
if isinstance(manager, MultilingualManager):
return
if manager.__class__ is Manager:
manager.__class__ = MultilingualManager
else:
class NewMultilingualManager(MultilingualManager, manager.__class__,
MultilingualQuerysetManager):
_old_module = manager.__module__
_old_class = manager.__class__.__name__
def deconstruct(self):
return (
False, # as_manager
'%s.%s' % (self._old_module, self._old_class), # manager_class
None, # qs_class
self._constructor_args[0], # args
self._constructor_args[1], # kwargs
)
manager.__class__ = NewMultilingualManager
def add_manager(model):
"""
Monkey patches the original model to use MultilingualManager instead of
@ -188,51 +203,18 @@ def add_manager(model):
if model._meta.abstract:
return
def patch_manager_class(manager):
if isinstance(manager, MultilingualManager):
return
if manager.__class__ is Manager:
manager.__class__ = MultilingualManager
else:
class NewMultilingualManager(MultilingualManager, manager.__class__,
MultilingualQuerysetManager):
if VERSION < (1, 10):
use_for_related_fields = getattr(
manager.__class__,
"use_for_related_fields",
not has_custom_queryset(manager),
)
_old_module = manager.__module__
_old_class = manager.__class__.__name__
def deconstruct(self):
return (
False, # as_manager
'%s.%s' % (self._old_module, self._old_class), # manager_class
None, # qs_class
self._constructor_args[0], # args
self._constructor_args[1], # kwargs
)
manager.__class__ = NewMultilingualManager
if NEW_MANAGER_API:
# Inspired by django.db.models.options.Options.managers (find all
# managers by following the normal Python MRO rules), but keeps the
# original managers instead of making copies.
managers = []
seen = set()
bases = (b for b in model.mro() if hasattr(b, '_meta'))
for base in bases:
for manager in base._meta.local_managers:
if manager.name in seen:
continue
managers.append(manager)
seen.add(manager.name)
else:
managers = ((getattr(model, x[1]) for x in
model._meta.concrete_managers + model._meta.abstract_managers))
# Inspired by django.db.models.options.Options.managers (find all
# managers by following the normal Python MRO rules), but keeps the
# original managers instead of making copies.
managers = []
seen = set()
bases = [b for b in model.mro() if hasattr(b, '_meta')]
for base in bases:
for manager in base._meta.local_managers:
if manager.name in seen:
continue
managers.append(manager)
seen.add(manager.name)
for current_manager in managers:
prev_class = current_manager.__class__
@ -245,10 +227,8 @@ def add_manager(model):
# share the same class.
model._default_manager.__class__ = current_manager.__class__
patch_manager_class(model._base_manager)
if VERSION >= (1, 10):
model._meta.base_manager_name = 'objects'
if hasattr(model._meta, "_expire_cache"):
model._meta._expire_cache()
model._meta.base_manager_name = 'objects'
model._meta._expire_cache()
def patch_constructor(model):
@ -259,12 +239,11 @@ def patch_constructor(model):
def new_init(self, *args, **kwargs):
self._mt_init = True
if NEW_DEFERRED_API or not self._deferred:
populate_translation_fields(self.__class__, kwargs)
for key, val in list(kwargs.items()):
new_key = rewrite_lookup_key(model, key)
# Old key is intentionally left in case old_init wants to play with it
kwargs.setdefault(new_key, val)
populate_translation_fields(self.__class__, kwargs)
for key, val in list(kwargs.items()):
new_key = rewrite_lookup_key(model, key)
# Old key is intentionally left in case old_init wants to play with it
kwargs.setdefault(new_key, val)
old_init(self, *args, **kwargs)
model.__init__ = new_init
@ -328,37 +307,6 @@ def patch_refresh_from_db(model):
model.refresh_from_db = new_refresh_from_db
def patch_metaclass(model):
"""
Monkey patches original model metaclass to exclude translated fields on deferred subclasses.
"""
old_mcs = model.__class__
class translation_deferred_mcs(old_mcs):
"""
This metaclass is essential for deferred subclasses (obtained via only/defer) to work.
When deferred subclass is created, some translated fields descriptors could be overridden
by DeferredAttribute - which would cause translation retrieval to fail.
Prevent this from happening with deleting those attributes from class being created.
This metaclass would be called from django.db.models.query_utils.deferred_class_factory
"""
def __new__(cls, name, bases, attrs):
if attrs.get('_deferred', False):
opts = translator.get_options_for_model(model)
were_deferred = set()
for field_name in opts.fields.keys():
if attrs.pop(field_name, None):
# Field was deferred. Store this for future reference.
were_deferred.add(field_name)
if len(were_deferred):
attrs['_fields_were_deferred'] = were_deferred
return super(translation_deferred_mcs, cls).__new__(cls, name, bases, attrs)
# Assign to __metaclass__ wouldn't work, since metaclass search algorithm check for __class__.
# http://docs.python.org/2/reference/datamodel.html#__metaclass__
model.__class__ = translation_deferred_mcs
def delete_cache_fields(model):
opts = model._meta
cached_attrs = ('_field_cache', '_field_name_cache', '_name_map', 'fields', 'concrete_fields',
@ -431,7 +379,7 @@ def patch_related_object_descriptor_caching(ro_descriptor):
class NewSingleObjectDescriptor(LanguageCacheSingleObjectDescriptor, ro_descriptor.__class__):
pass
if VERSION[0] == 2:
if django.VERSION[0] == 2:
ro_descriptor.related.get_cache_name = partial(
NewSingleObjectDescriptor.get_cache_name,
ro_descriptor,
@ -505,11 +453,11 @@ class Translator(object):
add_translation_fields(model, opts)
# Delete all fields cache for related model (parent and children)
related = ((
related = (
f for f in model._meta.get_fields()
if (f.one_to_many or f.one_to_one) and
f.auto_created
) if NEW_RELATED_API else model._meta.get_all_related_objects())
)
for related_obj in related:
delete_cache_fields(related_obj.model)
@ -521,19 +469,12 @@ class Translator(object):
patch_constructor(model)
# Connect signal for model
if NEW_DEFERRED_API:
post_init.connect(delete_mt_init, sender=model)
else:
# deferred models have their own classes and the `sender` does not match.
# Connect signal for all models.
post_init.connect(delete_mt_init, dispatch_uid="modeltranslation")
post_init.connect(delete_mt_init, sender=model)
# Patch clean_fields to verify form field clearing
patch_clean_fields(model)
# Patch __metaclass__ and other methods to allow deferring to work
if not NEW_DEFERRED_API:
patch_metaclass(model)
patch_get_deferred_fields(model)
patch_refresh_from_db(model)
@ -559,24 +500,18 @@ class Translator(object):
setattr(model, field.get_attname(), desc)
# Set related field names on other model
if NEW_RELATED_API and not field.remote_field.is_hidden():
if not field.remote_field.is_hidden():
other_opts = self._get_options_for_model(field.remote_field.model)
other_opts.related = True
other_opts.related_fields.append(field.related_query_name())
# Add manager in case of non-registered model
add_manager(field.remote_field.model)
elif not NEW_RELATED_API and not field.rel.is_hidden():
other_opts = self._get_options_for_model(field.rel.to)
other_opts.related = True
other_opts.related_fields.append(field.related_query_name())
add_manager(field.rel.to) # Add manager in case of non-registered model
if isinstance(field, OneToOneField):
# Fix translated_field caching for SingleRelatedObjectDescriptor
sro_descriptor = (
getattr(field.remote_field.model, field.remote_field.get_accessor_name())
if NEW_RELATED_API
else getattr(field.rel.to, field.related.get_accessor_name()))
)
patch_related_object_descriptor_caching(sro_descriptor)
def unregister(self, model_or_iterable):
@ -619,8 +554,6 @@ class Translator(object):
Returns an instance of translation options with translated fields
defined for the ``model`` and inherited from superclasses.
"""
if not NEW_DEFERRED_API and model._deferred:
model = model._meta.proxy_for_model
if model not in self._registry:
# Create a new type for backwards compatibility.
opts = type("%sTranslationOptions" % model.__name__,