def add_select_related(self, fields): """ Sets up the select_related data structure so that we only select certain related models (as opposed to all models, when self.select_related=True). """ new_fields = [] opts = self.model._meta # There is not actually any useful code, all this is to handle deprecated arguments. for field_name in fields: if field_name.startswith('translations'): new_name = None if field_name == 'translations': new_name = '%s_%s' % (TRANSLATION_FIELD_NAME, sanitize_language_code(get_active())) elif '_' in field_name: dummy, language_code = field_name.rsplit('_', 1) if language_code in get_all(): new_name = '%s_%s' % (TRANSLATION_FIELD_NAME, sanitize_language_code(language_code)) if new_name: msg = "Using '%s' in select_related is deprecated, use '%s' or '%s' instead." warnings.warn(msg % (field_name, TRANSLATION_FIELD_NAME, new_name), DeprecationWarning) new_fields.append(TRANSLATION_FIELD_NAME) new_fields.append(new_name) continue # In all other cases use the old name new_fields.append(field_name) new_fields = set(new_fields) return super(MultilingualQuery, self).add_select_related(new_fields)
def __get__(self, instance, instance_type=None): """ Returns field translation or None """ if instance is None: return self translation_model = self.model._meta.translation_model # Find language codes to be tried lang_codes = [self.language_code] if self._fallback: lang_codes += get_fallbacks(self.language_code) for lang_code in lang_codes: # Find translation translation_name = '%s_%s' % (TRANSLATION_FIELD_NAME, sanitize_language_code(lang_code)) try: # Translation is nullable, so it may return None translation = getattr(instance, translation_name) except translation_model.DoesNotExist: translation = None if translation is None: # Translation does not exist, try another language continue # Once we have the translation object we return what's there return getattr(translation, self._field_name) return None
def __init__(self, field_name, language_code=None, fallback=False): self._field_name = field_name self._language_code = language_code self._fallback = fallback name = field_name if language_code is not None: name = '%s_%s' % (name, sanitize_language_code(language_code)) if fallback: name = '%s_%s' % (name, FALLBACK_FIELD_SUFFIX) self.name = name super(TranslationProxyField, self).__init__()
def expand_lookup(opts, field_name): """ Utility that expands simple multilingual lookup to lookup which can be handled by DJango ORM. """ # Check if field is a translation field = _get_proxy_or_none(opts, field_name) if field is None: # Not a multilingual lookup, return return field_name # Multilingual field, add 'TranslationRelation' to lookup translation_name = '%s_%s' % (TRANSLATION_FIELD_NAME, sanitize_language_code(field.language_code)) return LOOKUP_SEP.join((translation_name, field.field_name))
def __init__(self, to, base_name, language_code=None, **kwargs): self._base_name = base_name self._language_code = language_code # Create the field name if language_code: name = '%s_%s' % (base_name, sanitize_language_code(language_code)) else: name = base_name kwargs['name'] = name # Disable any modifications of this field kwargs['editable'] = False kwargs['serialize'] = False # Define 'rel' object kwargs['rel'] = TranslationRel(self, to) # Let queries to fill master object into translation cache, e.g. in select_related. kwargs['unique'] = True kwargs['null'] = True to_fields = ['master'] super(TranslationRelation, self).__init__(to, [], to_fields, **kwargs)
def __set__(self, instance, value): """ Sets field translation """ translation_model = self.model._meta.translation_model # Find translation translation_name = '%s_%s' % (TRANSLATION_FIELD_NAME, sanitize_language_code(self.language_code)) try: # Translation is nullable, so it may return None translation = getattr(instance, translation_name) except translation_model.DoesNotExist: translation = None if translation is None: # Translation does not exist, create one translation = translation_model(master=instance, language_code=self.language_code) setattr(instance, translation_name, translation) # Set the field translation setattr(translation, self._field_name, value)
def get_cache_name(self): # The field for active language needs to use the cache for that language return '_%s_%s_cache' % (self._base_name, sanitize_language_code(self.language_code))
def test_sanitize_language_code(self): self.assertEqual(sanitize_language_code('cs'), 'cs') self.assertEqual(sanitize_language_code('en'), 'en') self.assertEqual(sanitize_language_code('en-us'), 'en_us')