From 84115df1dcbc939fa181da580918b336ff3718ac Mon Sep 17 00:00:00 2001 From: Sergey Tereschenko Date: Sat, 16 Feb 2019 15:12:53 +0200 Subject: [PATCH] cleanup: remove code for old djago --- modeltranslation/translator.py | 169 ++++++++++----------------------- 1 file changed, 51 insertions(+), 118 deletions(-) diff --git a/modeltranslation/translator.py b/modeltranslation/translator.py index 962d25d..f6f6b57 100644 --- a/modeltranslation/translator.py +++ b/modeltranslation/translator.py @@ -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__,