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)
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)
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