示例#1
0
    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)