def _register_single_model(self, model, opts): # Now, when all fields are initialized and inherited, validate configuration. opts.validate() # Mark the object explicitly as registered -- registry caches # options of all models, registered or not. opts.registered = True # Add translation fields to the model. if model._meta.proxy: delete_cache_fields(model) else: add_translation_fields(model, opts) # Delete all fields cache for related model (parent and children) 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) # Set MultilingualManager add_manager(model) # Patch __init__ to rewrite fields 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") # 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) # Substitute original field with descriptor model_fallback_languages = getattr(opts, 'fallback_languages', None) model_fallback_values = getattr(opts, 'fallback_values', NONE) model_fallback_undefined = getattr(opts, 'fallback_undefined', NONE) for field_name in opts.local_fields.keys(): field = model._meta.get_field(field_name) field_fallback_value = parse_field(model_fallback_values, field_name, NONE) field_fallback_undefined = parse_field(model_fallback_undefined, field_name, NONE) descriptor = TranslationFieldDescriptor( field, fallback_languages=model_fallback_languages, fallback_value=field_fallback_value, fallback_undefined=field_fallback_undefined) setattr(model, field_name, descriptor) if isinstance(field, ForeignKey): # We need to use a special descriptor so that # _id fields on translated ForeignKeys work # as expected. desc = TranslatedRelationIdDescriptor(field_name, model_fallback_languages) setattr(model, field.get_attname(), desc) # Set related field names on other model if NEW_RELATED_API and not field.remote_field.is_hidden(): other_opts = self._get_options_for_model(field.remote_field.to) 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.to) 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.to, 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 register(self, model_or_iterable, opts_class=None, **options): """ Registers the given model(s) with the given translation options. The model(s) should be Model classes, not instances. Fields declared for translation on a base class are inherited by subclasses. If the model or one of its subclasses is already registered for translation, this will raise an exception. """ if isinstance(model_or_iterable, ModelBase): model_or_iterable = [model_or_iterable] for model in model_or_iterable: # Ensure that a base is not registered after a subclass (_registry # is closed with respect to taking bases, so we can just check if # we've seen the model). if model in self._registry: if self._registry[model].registered: raise AlreadyRegistered( 'Model "%s" is already registered for translation' % model.__name__) else: descendants = [ d.__name__ for d in self._registry.keys() if issubclass(d, model) and d != model ] raise DescendantRegistered( 'Model "%s" cannot be registered after its subclass' ' "%s"' % (model.__name__, descendants[0])) # Find inherited fields and create options instance for the model. opts = self._get_options_for_model(model, opts_class, **options) # Now, when all fields are initialized and inherited, validate configuration. opts.validate() # Mark the object explicitly as registered -- registry caches # options of all models, registered or not. opts.registered = True # Add translation fields to the model. if model._meta.proxy: delete_cache_fields(model) else: add_translation_fields(model, opts) # Delete all fields cache for related model (parent and children) for related_obj in model._meta.get_all_related_objects(): delete_cache_fields(related_obj.model) # Set MultilingualManager add_manager(model) # Patch __init__ to rewrite fields patch_constructor(model) # Connect signal for model 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 patch_metaclass(model) patch_get_deferred_fields(model) # Substitute original field with descriptor model_fallback_languages = getattr(opts, 'fallback_languages', None) model_fallback_values = getattr(opts, 'fallback_values', NONE) model_fallback_undefined = getattr(opts, 'fallback_undefined', NONE) for field_name in opts.local_fields.keys(): field = model._meta.get_field(field_name) field_fallback_value = parse_field(model_fallback_values, field_name, NONE) field_fallback_undefined = parse_field( model_fallback_undefined, field_name, NONE) descriptor = TranslationFieldDescriptor( field, fallback_languages=model_fallback_languages, fallback_value=field_fallback_value, fallback_undefined=field_fallback_undefined) setattr(model, field_name, descriptor) if isinstance(field, ForeignKey): # We need to use a special descriptor so that # _id fields on translated ForeignKeys work # as expected. desc = TranslatedRelationIdDescriptor( field_name, model_fallback_languages) setattr(model, field.get_attname(), desc) # Set related field names on other model if 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.rel.to, field.related.get_accessor_name()) patch_related_object_descriptor_caching(sro_descriptor)
def register(self, model_or_iterable, translation_opts, **options): """ Registers the given model(s) with the given translation options. The model(s) should be Model classes, not instances. If a model is already registered for translation, this will raise AlreadyRegistered. """ if isinstance(model_or_iterable, ModelBase): model_or_iterable = [model_or_iterable] for model in model_or_iterable: if model in self._registry: raise AlreadyRegistered('The model %s is already registered ' 'for translation' % model.__name__) # If we got **options then dynamically construct a subclass of # translation_opts with those **options. if options: # For reasons I don't quite understand, without a __module__ # the created class appears to "live" in the wrong place, # which causes issues later on. options['__module__'] = __name__ translation_opts = type( "%sTranslationOptions" % model.__name__, (translation_opts,), options) # Store the translation class associated to the model self._registry[model] = translation_opts # Add the localized fields to the model and store the names of # these fields in the model's translation options for faster lookup # later on. translation_opts.localized_fieldnames = add_localized_fields(model) # Create a reverse dict mapping the localized_fieldnames to the # original fieldname rev_dict = dict() for orig_name, loc_names in \ translation_opts.localized_fieldnames.items(): for ln in loc_names: rev_dict[ln] = orig_name translation_opts.localized_fieldnames_rev = rev_dict # Delete all fields cache for related model (parent and children) for related_obj in model._meta.get_all_related_objects(): delete_cache_fields(related_obj.model) # Set MultilingualManager add_manager(model) # Patch __init__ to rewrite fields patch_constructor(model) # Substitute original field with descriptor model_fallback_values = getattr( translation_opts, 'fallback_values', None) model_fallback_languages = getattr( translation_opts, 'fallback_languages', None) for field_name in translation_opts.fields: if model_fallback_values is None: field_fallback_value = None elif isinstance(model_fallback_values, dict): field_fallback_value = model_fallback_values.get( field_name, None) else: field_fallback_value = model_fallback_values descriptor = TranslationFieldDescriptor( model._meta.get_field(field_name), fallback_value=field_fallback_value, fallback_languages=model_fallback_languages) setattr(model, field_name, descriptor)
def register(self, model_or_iterable, translation_opts, **options): """ Registers the given model(s) with the given translation options. The model(s) should be Model classes, not instances. If a model is already registered for translation, this will raise AlreadyRegistered. """ # Don't import the humongous validation code unless required if translation_opts and settings.DEBUG: from django.contrib.admin.validation import validate else: validate = lambda model, adminclass: None #if not translation_opts: #translation_opts = TranslationOptions if isinstance(model_or_iterable, ModelBase): model_or_iterable = [model_or_iterable] for model in model_or_iterable: if model in self._registry: raise AlreadyRegistered('The model %s is already registered ' 'for translation' % model.__name__) # If we got **options then dynamically construct a subclass of # translation_opts with those **options. if options: # For reasons I don't quite understand, without a __module__ # the created class appears to "live" in the wrong place, # which causes issues later on. options['__module__'] = __name__ translation_opts = type("%sAdmin" % model.__name__, (translation_opts,), options) # Validate (which might be a no-op) #validate(translation_opts, model) # Store the translation class associated to the model self._registry[model] = translation_opts # Get the content type of the original model and store it on the # translation options for faster lookup later on. #translation_opts.model_ct = \ #ContentType.objects.get_for_model(model) # Add the localized fields to the model and store the names of # these fields in the model's translation options for faster lookup # later on. translation_opts.localized_fieldnames = add_localized_fields(model) # Create a reverse dict mapping the localized_fieldnames to the # original fieldname rev_dict = dict() for orig_name, loc_names in\ translation_opts.localized_fieldnames.items(): for ln in loc_names: rev_dict[ln] = orig_name translation_opts.localized_fieldnames_rev = rev_dict model_fallback_values = getattr(translation_opts, 'fallback_values', None) for field_name in translation_opts.fields: # TODO: Check if fallback_value is set to a type that the field # expects and raise ImproperlyConfigured in case it doesn't. if model_fallback_values is None: field_fallback_value = None elif isinstance(model_fallback_values, dict): field_fallback_value = model_fallback_values.get(field_name, None) else: field_fallback_value = model_fallback_values field = model._meta.get_field(field_name) field_class_name = field.rel.__class__.__name__ if field_class_name in ('ManyToOneRel', 'OneToOneRel'): descriptor = RelatedTranslationFieldDescriptor(field_name, fallback_value=field_fallback_value) elif field_class_name == 'ManyToManyRel': descriptor = ManyToManyTranslationFieldDescriptor(field_name, fallback_value=field_fallback_value) else: descriptor = TranslationFieldDescriptor(field_name, fallback_value=field_fallback_value) setattr(model, field_name, descriptor)
def register(self, model_or_iterable, translation_opts, **options): """ Registers the given model(s) with the given translation options. The model(s) should be Model classes, not instances. If a model is already registered for translation, this will raise AlreadyRegistered. """ # Don't import the humongous validation code unless required if translation_opts and settings.DEBUG: from django.contrib.admin.validation import validate else: validate = lambda model, adminclass: None #if not translation_opts: #translation_opts = TranslationOptions if isinstance(model_or_iterable, ModelBase): model_or_iterable = [model_or_iterable] for model in model_or_iterable: if model in self._registry: raise AlreadyRegistered('The model %s is already registered ' 'for translation' % model.__name__) # If we got **options then dynamically construct a subclass of # translation_opts with those **options. if options: # For reasons I don't quite understand, without a __module__ # the created class appears to "live" in the wrong place, # which causes issues later on. options['__module__'] = __name__ translation_opts = type("%sAdmin" % model.__name__, (translation_opts, ), options) # Validate (which might be a no-op) #validate(translation_opts, model) # Store the translation class associated to the model self._registry[model] = translation_opts # Get the content type of the original model and store it on the # translation options for faster lookup later on. #translation_opts.model_ct = \ #ContentType.objects.get_for_model(model) # Add the localized fields to the model and store the names of # these fields in the model's translation options for faster lookup # later on. translation_opts.localized_fieldnames = add_localized_fields(model) # Create a reverse dict mapping the localized_fieldnames to the # original fieldname rev_dict = dict() for orig_name, loc_names in\ translation_opts.localized_fieldnames.items(): for ln in loc_names: rev_dict[ln] = orig_name translation_opts.localized_fieldnames_rev = rev_dict # Delete all fields cache for related model (parent and children) related_classes = tuple(model.__bases__) \ + tuple(model.__subclasses__()) for related_model in related_classes: if related_model != models.Model \ and issubclass(related_model, models.Model): delete_cache_fields(related_model) model_fallback_values =\ getattr(translation_opts, 'fallback_values', None) for field_name in translation_opts.fields: if model_fallback_values is None: field_fallback_value = None elif isinstance(model_fallback_values, dict): field_fallback_value =\ model_fallback_values.get(field_name, None) else: field_fallback_value = model_fallback_values setattr(model, field_name, TranslationFieldDescriptor(field_name,\ fallback_value=field_fallback_value))