def has_translation(self, language_code=None, related_name=None): """ Return whether a translation for the given language exists. Defaults to the current language code. .. versionadded 1.2 Added the ``related_name`` parameter. """ if language_code is None: language_code = self._current_language meta = self._parler_meta._get_extension_by_related_name(related_name) try: # Check the local cache directly, and the answer is known. # NOTE this may also return newly auto created translations which are not saved yet. return self._translations_cache[meta.model][language_code] is not MISSING except KeyError: # Try to fetch from the cache first. # If the cache returns the fallback, it means the original does not exist. object = get_cached_translation(self, language_code, related_name=related_name, use_fallback=True) if object is not None: return object.language_code == language_code try: # Fetch from DB, fill the cache. self._get_translated_model(language_code, use_fallback=False, auto_create=False, meta=meta) except meta.model.DoesNotExist: return False else: return True
def has_translation(self, language_code=None, related_name=None): """ Return whether a translation for the given language exists. Defaults to the current language code. .. versionadded 1.2 Added the ``related_name`` parameter. """ if language_code is None: language_code = self._current_language meta = self._parler_meta._get_extension_by_related_name(related_name) try: # Check the local cache directly, and the answer is known. # NOTE this may also return newly auto created translations which are not saved yet. return self._translations_cache[ meta.model][language_code] is not MISSING except KeyError: # If there is a prefetch, will be using that. # However, don't assume the prefetch contains all possible languages. # With Django 1.8, there are custom Prefetch objects. # TODO: improve this, detect whether this is the case. if language_code in self._read_prefetched_translations(meta=meta): return True # Try to fetch from the cache first. # If the cache returns the fallback, it means the original does not exist. object = get_cached_translation(self, language_code, related_name=related_name, use_fallback=True) if object is not None: return object.language_code == language_code try: # Fetch from DB, fill the cache. self._get_translated_model(language_code, use_fallback=False, auto_create=False, meta=meta) except meta.model.DoesNotExist: return False else: return True
def has_translation(self, language_code=None, related_name=None): """ Return whether a translation for the given language exists. Defaults to the current language code. .. versionadded 1.2 Added the ``related_name`` parameter. """ if language_code is None: language_code = self._current_language if language_code is None: raise ValueError(get_null_language_error()) meta = self._parler_meta._get_extension_by_related_name(related_name) try: # Check the local cache directly, and the answer is known. # NOTE this may also return newly auto created translations which are not saved yet. return self._translations_cache[meta.model][language_code] is not MISSING except KeyError: # If there is a prefetch, will be using that. # However, don't assume the prefetch contains all possible languages. # With Django 1.8, there are custom Prefetch objects. # TODO: improve this, detect whether this is the case. if language_code in self._read_prefetched_translations(meta=meta): return True # Try to fetch from the cache first. # If the cache returns the fallback, it means the original does not exist. object = get_cached_translation(self, language_code, related_name=related_name, use_fallback=True) if object is not None: return object.language_code == language_code try: # Fetch from DB, fill the cache. self._get_translated_model(language_code, use_fallback=False, auto_create=False, meta=meta) except meta.model.DoesNotExist: return False else: return True
def has_translation(self, language_code=None, related_name=None): """ Return whether a translation for the given language exists. Defaults to the current language code. .. versionadded 1.2 Added the ``related_name`` parameter. """ if language_code is None: language_code = self._current_language meta = self._parler_meta._get_extension_by_related_name(related_name) try: # Check the local cache directly, and the answer is known. # NOTE this may also return newly auto created translations which are not saved yet. return self._translations_cache[ meta.model][language_code] is not MISSING except KeyError: # Try to fetch from the cache first. # If the cache returns the fallback, it means the original does not exist. object = get_cached_translation(self, language_code, related_name=related_name, use_fallback=True) if object is not None: return object.language_code == language_code try: # Fetch from DB, fill the cache. self._get_translated_model(language_code, use_fallback=False, auto_create=False, meta=meta) except meta.model.DoesNotExist: return False else: return True
def _get_translated_model(self, language_code=None, use_fallback=False, auto_create=False): """ Fetch the translated fields model. """ if not self._translations_model or not self._translations_field: raise ImproperlyConfigured("No translation is assigned to the current model!") if not language_code: language_code = self._current_language # 1. fetch the object from the local cache try: object = self._translations_cache[language_code] # If cached object indicates the language doesn't exist, need to query the fallback. if object is not None: return object except KeyError: # 2. No cache, need to query # Check that this object already exists, would be pointless otherwise to check for a translation. if not self._state.adding and self.pk: qs = self._get_translated_queryset() if qs._prefetch_done: # 2.1, use prefetched data # If the object is not found in the prefetched data (which contains all translations), # it's pointless to check for memcached (2.2) or perform a single query (2.3) for object in qs: if object.language_code == language_code: self._translations_cache[language_code] = object _cache_translation(object) # Store in memcached return object else: # 2.2, fetch from memcached object = get_cached_translation(self, language_code, use_fallback=use_fallback) if object is not None: # Track in local cache if object.language_code != language_code: self._translations_cache[language_code] = None # Set fallback marker self._translations_cache[object.language_code] = object return object else: # 2.3, fetch from database try: object = qs.get(language_code=language_code) except self._translations_model.DoesNotExist: pass else: self._translations_cache[language_code] = object _cache_translation(object) # Store in memcached return object # Not in cache, or default. # Not fetched from DB # 3. Auto create? if auto_create: # Auto create policy first (e.g. a __set__ call) object = self._translations_model( language_code=language_code, master=self # ID might be None at this point ) self._translations_cache[language_code] = object # Not stored in memcached here yet, first fill + save it. return object # 4. Fallback? fallback_msg = None lang_dict = get_language_settings(language_code) if use_fallback and (lang_dict['fallback'] != language_code): # Explicitly set a marker for the fact that this translation uses the fallback instead. # Avoid making that query again. self._translations_cache[language_code] = None # None value is the marker. if not self._state.adding or self.pk: _cache_translation_needs_fallback(self, language_code) # Jump to fallback language, return directly. # Don't cache under this language_code try: return self._get_translated_model(lang_dict['fallback'], use_fallback=False, auto_create=auto_create) except self._translations_model.DoesNotExist: fallback_msg = " (tried fallback {0})".format(lang_dict['fallback']) # None of the above, bail out! raise self._translations_model.DoesNotExist( "{0} does not have a translation for the current language!\n" "{0} ID #{1}, language={2}{3}".format(self._meta.verbose_name, self.pk, language_code, fallback_msg or '' ))
def _get_translated_model(self, language_code=None, use_fallback=False, auto_create=False, meta=None): """ Fetch the translated fields model. """ if self._parler_meta is None: raise ImproperlyConfigured("No translation is assigned to the current model!") if self._translations_cache is None: raise RuntimeError("Accessing translated fields before super.__init__() is not possible.") if not language_code: language_code = self._current_language if meta is None: meta = self._parler_meta.root # work on base model by default local_cache = self._translations_cache[meta.model] # 1. fetch the object from the local cache try: object = local_cache[language_code] # If cached object indicates the language doesn't exist, need to query the fallback. if object is not MISSING: return object except KeyError: # 2. No cache, need to query # Check that this object already exists, would be pointless otherwise to check for a translation. if not self._state.adding and self.pk is not None: prefetch = self._get_prefetched_translations(meta=meta) if prefetch is not None: # 2.1, use prefetched data # If the object is not found in the prefetched data (which contains all translations), # it's pointless to check for memcached (2.2) or perform a single query (2.3) for object in prefetch: if object.language_code == language_code: local_cache[language_code] = object _cache_translation(object) # Store in memcached return object else: # 2.2, fetch from memcached object = get_cached_translation(self, language_code, related_name=meta.rel_name, use_fallback=use_fallback) if object is not None: # Track in local cache if object.language_code != language_code: local_cache[language_code] = MISSING # Set fallback marker local_cache[object.language_code] = object return object elif local_cache.get(language_code, None) is MISSING: # If get_cached_translation() explicitly set the "does not exist" marker, # there is no need to try a database query. pass else: # 2.3, fetch from database try: object = self._get_translated_queryset(meta).get(language_code=language_code) except meta.model.DoesNotExist: pass else: local_cache[language_code] = object _cache_translation(object) # Store in memcached return object # Not in cache, or default. # Not fetched from DB # 3. Auto create? if auto_create: # Auto create policy first (e.g. a __set__ call) kwargs = { 'language_code': language_code, } if self.pk: # ID might be None at this point, and Django 1.8 does not allow that. kwargs['master'] = self object = meta.model(**kwargs) local_cache[language_code] = object # Not stored in memcached here yet, first fill + save it. return object # 4. Fallback? fallback_msg = None lang_dict = get_language_settings(language_code) if language_code not in local_cache: # Explicitly set a marker for the fact that this translation uses the fallback instead. # Avoid making that query again. local_cache[language_code] = MISSING # None value is the marker. if not self._state.adding or self.pk is not None: _cache_translation_needs_fallback(self, language_code, related_name=meta.rel_name) fallback_choices = [lang_dict['code']] + list(lang_dict['fallbacks']) if use_fallback and fallback_choices: # Jump to fallback language, return directly. # Don't cache under this language_code for fallback_lang in fallback_choices: if fallback_lang == language_code: # Skip the current language, could also be fallback 1 of 2 choices continue try: return self._get_translated_model(fallback_lang, use_fallback=False, auto_create=auto_create, meta=meta) except meta.model.DoesNotExist: pass fallback_msg = " (tried fallbacks {0})".format(', '.join(lang_dict['fallbacks'])) # None of the above, bail out! raise meta.model.DoesNotExist( "{0} does not have a translation for the current language!\n" "{0} ID #{1}, language={2}{3}".format(self._meta.verbose_name, self.pk, language_code, fallback_msg or '' ))
def _get_translated_model(self, language_code=None, use_fallback=False, auto_create=False): """ Fetch the translated fields model. """ if not self._translations_model or not self._translations_field: raise ImproperlyConfigured( "No translation is assigned to the current model!") if not language_code: language_code = self._current_language # 1. fetch the object from the local cache try: object = self._translations_cache[language_code] # If cached object indicates the language doesn't exist, need to query the fallback. if object is not None: return object except KeyError: # 2. No cache, need to query # Check that this object already exists, would be pointless otherwise to check for a translation. if not self._state.adding and self.pk: qs = self._get_translated_queryset() if qs._prefetch_done: # 2.1, use prefetched data # If the object is not found in the prefetched data (which contains all translations), # it's pointless to check for memcached (2.2) or perform a single query (2.3) for object in qs: if object.language_code == language_code: self._translations_cache[language_code] = object _cache_translation(object) # Store in memcached return object else: # 2.2, fetch from memcached object = get_cached_translation(self, language_code, use_fallback=use_fallback) if object is not None: # Track in local cache if object.language_code != language_code: self._translations_cache[ language_code] = None # Set fallback marker self._translations_cache[object.language_code] = object return object else: # 2.3, fetch from database try: object = qs.get(language_code=language_code) except self._translations_model.DoesNotExist: pass else: self._translations_cache[language_code] = object _cache_translation(object) # Store in memcached return object # Not in cache, or default. # Not fetched from DB # 3. Auto create? if auto_create: # Auto create policy first (e.g. a __set__ call) object = self._translations_model( language_code=language_code, master=self # ID might be None at this point ) self._translations_cache[language_code] = object # Not stored in memcached here yet, first fill + save it. return object # 4. Fallback? fallback_msg = None lang_dict = get_language_settings(language_code) if use_fallback and (lang_dict['fallback'] != language_code): # Explicitly set a marker for the fact that this translation uses the fallback instead. # Avoid making that query again. self._translations_cache[ language_code] = None # None value is the marker. if not self._state.adding or self.pk: _cache_translation_needs_fallback(self, language_code) # Jump to fallback language, return directly. # Don't cache under this language_code try: return self._get_translated_model(lang_dict['fallback'], use_fallback=False, auto_create=auto_create) except self._translations_model.DoesNotExist: fallback_msg = " (tried fallback {0})".format( lang_dict['fallback']) # None of the above, bail out! raise self._translations_model.DoesNotExist( "{0} does not have a translation for the current language!\n" "{0} ID #{1}, language={2}{3}".format(self._meta.verbose_name, self.pk, language_code, fallback_msg or ''))
def _get_translated_model(self, language_code=None, use_fallback=False, auto_create=False, meta=None): """ Fetch the translated fields model. """ if self._parler_meta is None: raise ImproperlyConfigured( "No translation is assigned to the current model!") if self._translations_cache is None: raise RuntimeError( "Accessing translated fields before super.__init__() is not possible." ) if not language_code: language_code = self._current_language if meta is None: meta = self._parler_meta.root # work on base model by default local_cache = self._translations_cache[meta.model] # 1. fetch the object from the local cache try: object = local_cache[language_code] # If cached object indicates the language doesn't exist, need to query the fallback. if object is not MISSING: return object except KeyError: # 2. No cache, need to query # Check that this object already exists, would be pointless otherwise to check for a translation. if not self._state.adding and self.pk is not None: prefetch = self._get_prefetched_translations(meta=meta) if prefetch is not None: # 2.1, use prefetched data # If the object is not found in the prefetched data (which contains all translations), # it's pointless to check for memcached (2.2) or perform a single query (2.3) for object in prefetch: if object.language_code == language_code: local_cache[language_code] = object _cache_translation(object) # Store in memcached return object else: # 2.2, fetch from memcached object = get_cached_translation(self, language_code, related_name=meta.rel_name, use_fallback=use_fallback) if object is not None: # Track in local cache if object.language_code != language_code: local_cache[ language_code] = MISSING # Set fallback marker local_cache[object.language_code] = object return object elif local_cache.get(language_code, None) is MISSING: # If get_cached_translation() explicitly set the "does not exist" marker, # there is no need to try a database query. pass else: # 2.3, fetch from database try: object = self._get_translated_queryset(meta).get( language_code=language_code) except meta.model.DoesNotExist: pass else: local_cache[language_code] = object _cache_translation(object) # Store in memcached return object # Not in cache, or default. # Not fetched from DB # 3. Auto create? if auto_create: # Auto create policy first (e.g. a __set__ call) kwargs = { 'language_code': language_code, } if self.pk: # ID might be None at this point, and Django 1.8 does not allow that. kwargs['master'] = self object = meta.model(**kwargs) local_cache[language_code] = object # Not stored in memcached here yet, first fill + save it. return object # 4. Fallback? fallback_msg = None lang_dict = get_language_settings(language_code) if language_code not in local_cache: # Explicitly set a marker for the fact that this translation uses the fallback instead. # Avoid making that query again. local_cache[language_code] = MISSING # None value is the marker. if not self._state.adding or self.pk is not None: _cache_translation_needs_fallback(self, language_code, related_name=meta.rel_name) if lang_dict['fallback'] != language_code and use_fallback: # Jump to fallback language, return directly. # Don't cache under this language_code try: return self._get_translated_model(lang_dict['fallback'], use_fallback=False, auto_create=auto_create, meta=meta) except meta.model.DoesNotExist: fallback_msg = " (tried fallback {0})".format( lang_dict['fallback']) # None of the above, bail out! raise meta.model.DoesNotExist( "{0} does not have a translation for the current language!\n" "{0} ID #{1}, language={2}{3}".format(self._meta.verbose_name, self.pk, language_code, fallback_msg or ''))
def _get_translated_model(self, language_code=None, use_fallback=False, auto_create=False): """ Fetch the translated fields model. """ if not self._translations_model or not self._translations_field: raise ImproperlyConfigured( "No translation is assigned to the current model!") if not language_code: language_code = self._current_language # 1. fetch the object from the local cache try: object = self._translations_cache[language_code] # If cached object indicates the language doesn't exist, need to query the fallback. if object is not None: return object except KeyError: # 2. No cache, need to query # Get via self.TRANSLATIONS_FIELD.get(..) so it also uses the prefetch/select_related cache. # Check that this object already exists, would be pointless otherwise to check for a translation. if not self._state.adding: # 2.1, fetch from memcache object = get_cached_translation(self, language_code) if object is not None: # Track in local cache self._translations_cache[language_code] = object return object else: # 2.2, fetch from database accessor = getattr(self, self._translations_field) try: object = accessor.get(language_code=language_code) except self._translations_model.DoesNotExist: pass else: self._translations_cache[language_code] = object _cache_translation(object) # Store in memcached return object # Not in cache, or default. # Not fetched from DB # 3. Auto create? if auto_create: # Auto create policy first (e.g. a __set__ call) object = self._translations_model( language_code=language_code, master=self # ID might be None at this point ) self._translations_cache[language_code] = object # Not stored in memcached here yet, first fill + save it. return object # 4. Fallback? fallback_msg = None lang_dict = get_language_settings(language_code) if use_fallback and (lang_dict['fallback'] != language_code): # Jump to fallback language, return directly. # Don't cache under this language_code self._translations_cache[ language_code] = None # explicit marker that language query was tried before. try: return self._get_translated_model(lang_dict['fallback'], use_fallback=False, auto_create=auto_create) except self._translations_model.DoesNotExist: fallback_msg = u" (tried fallback {0})".format( lang_dict['fallback']) # None of the above, bail out! raise self._translations_model.DoesNotExist( u"{0} does not have a translation for the current language!\n" u"{0} ID #{1}, language={2}{3}".format(self._meta.verbose_name, self.pk, language_code, fallback_msg or ''))
def _get_translated_model(self, language_code=None, use_fallback=False, auto_create=False): """ Fetch the translated fields model. """ if not self._translations_model or not self._translations_field: raise ImproperlyConfigured("No translation is assigned to the current model!") if not language_code: language_code = self._current_language # 1. fetch the object from the local cache try: object = self._translations_cache[language_code] # If cached object indicates the language doesn't exist, need to query the fallback. if object is not None: return object except KeyError: # 2. No cache, need to query # Get via self.TRANSLATIONS_FIELD.get(..) so it also uses the prefetch/select_related cache. # Check that this object already exists, would be pointless otherwise to check for a translation. if not self._state.adding: # 2.1, fetch from memcache object = get_cached_translation(self, language_code) if object is not None: # Track in local cache self._translations_cache[language_code] = object return object else: # 2.2, fetch from database accessor = getattr(self, self._translations_field) try: object = accessor.get(language_code=language_code) except self._translations_model.DoesNotExist: pass else: self._translations_cache[language_code] = object _cache_translation(object) # Store in memcached return object # Not in cache, or default. # Not fetched from DB # 3. Auto create? if auto_create: # Auto create policy first (e.g. a __set__ call) object = self._translations_model( language_code=language_code, master=self # ID might be None at this point ) self._translations_cache[language_code] = object # Not stored in memcached here yet, first fill + save it. return object # 4. Fallback? fallback_msg = None lang_dict = get_language_settings(language_code) if use_fallback and (lang_dict['fallback'] != language_code): # Jump to fallback language, return directly. # Don't cache under this language_code self._translations_cache[language_code] = None # explicit marker that language query was tried before. try: return self._get_translated_model(lang_dict['fallback'], use_fallback=False, auto_create=auto_create) except self._translations_model.DoesNotExist: fallback_msg = u" (tried fallback {0})".format(lang_dict['fallback']) # None of the above, bail out! raise self._translations_model.DoesNotExist( u"{0} does not have a translation for the current language!\n" u"{0} ID #{1}, language={2}{3}".format(self._meta.verbose_name, self.pk, language_code, fallback_msg or '' ))