Пример #1
0
    def add_select_related(self, fields):
        """
        If in fields is related_field for translations, will be replaced by fields in proper languages.
        """
        new_fields = []
        extra_select = {}
        opts = self.model._meta
        trans_opts = opts.translation_model._meta
        # TODO: fix this
        #related_name = trans_opts.related_name
        related_name = 'translations'

        translation_fields = [f.name for f in trans_opts.fields if f.name not in ('master', 'language_code')]

        for field in fields:
            # usual select_related
            if not field.startswith(related_name):
                new_fields.append(field)
                continue

            # get language
            if field == related_name:
                language_code = get_active()
            else:
                field_and_lang = field.rsplit('_', 1)
                # Coincidental field name might occur if language_code is not correct, do not do anything as 
                # select_related does not raise errors if used with incorrect fields
                if len(field_and_lang) != 2 or field_and_lang[1] not in get_all():
                    new_fields.append(field)
                    continue
                field, language_code = field_and_lang

            # This is main code of this method, build extra_select that might be used by fill_translation_cache
            for trans_field in translation_fields:
                extra_select[get_field_alias(trans_field, language_code)] = '%s.%s' % (
                    get_table_alias(trans_opts.db_table, language_code),
                    connection.ops.quote_name(trans_field)
                )

            # XXX: this is not safe if translation model has no fields, can it happen??

            # join translatable model (original) table if not joined yet
            alias = self.get_initial_alias()

            # join translation table if not joined yet
            translation_fields.remove(trans_opts.pk.name)
            self.setup_joins(
                ['%s_%s' % (translation_fields[0], language_code)], # any translated_field
                opts,
                alias,
                True,
                can_reuse = set([alias])
            )

        if extra_select:
            self.add_extra(extra_select, None, None, None, None, None)
        super(MultilingualQuery, self).add_select_related(new_fields)
Пример #2
0
    def _fill_translation_cache(self, language_code):
        """
				Fill the translation cache using information from query.extra_fields if any.
				"""
        # This can not be called in post_init because the extra fields are
        # assigned by QuerySet.iterator after model initialization.

        # unsaved instances does not have translations
        if not self.pk:
            return
            # skip if we already has translation, or we know there is not one
        if cache_state():
            self._translation_cache = cache.get(
                "ml_cache_%s_%s" % (self._meta.db_table, self.pk), self._translation_cache
            )
        if self._translation_cache.has_key(language_code):
            return

        c_trans_model = self._meta.translation_model

        # see if translation was in the query
        # WARNING: This must fail if we do not have all fields in query
        translation_data = {}
        for field_name in [f.attname for f in c_trans_model._meta.fields]:
            # We know values of language_code and master_id, so we does not expect them to be in query
            if field_name in ("language_code", "master_id"):
                continue

            try:
                translation_data[field_name] = getattr(self, get_field_alias(field_name, language_code))
            except AttributeError:
                # if any field is missing we can not store data in translation cache
                # and we need to use direct query
                translation_data = None
                break

        if translation_data is not None:
            translation = c_trans_model(language_code=language_code, master=self, **translation_data)
            self._translation_cache[language_code] = translation
        else:
            # If we do not have translation (e.g. was not part of query)
            # we will try direct query to load it
            try:
                # TODO, XXX: get correct related_name instead of 'translations' !!!
                self._translation_cache[language_code] = self.translations.get(language_code=language_code)
            except c_trans_model.DoesNotExist:
                # translation does not exist, we store None to avoid repetitive calls of this code
                self._translation_cache[language_code] = None
        cache.set("ml_cache_%s_%s" % (self._meta.db_table, self.pk), self._translation_cache, 3600)
Пример #3
0
    def _get_translation_from_select_related(self, language_code):
        c_trans_model = self._meta.translation_model

        # see if translation was in the query
        # WARNING: This must fail if we do not have all fields in query
        translation_data = {}
        for field_name in [f.attname for f in c_trans_model._meta.fields]:
            # We know values of language_code and master_id, so we does not expect them to be in query
            if field_name in ('language_code', 'master_id'):
                continue

            try:
                translation_data[field_name] = getattr(self, get_field_alias(field_name, language_code))
            except AttributeError:
                # if any field is missing we can not store data in translation cache
                # and we need to use direct query
                translation_data = None
                break

        if translation_data is not None:
            return c_trans_model(language_code=language_code, master=self, **translation_data)
        else:
            return None