hvad.manager

This module is where most of the functionality is implemented.

hvad.manager.FALLBACK_LANGUAGES

The default sequence for fallback languages, populates itself from settings.LANGUAGES, could possibly become a setting on it’s own at some point.

FieldTranslator

class hvad.manager.FieldTranslator

The cache mentioned in this class is the instance of the class itself, since it inherits dict.

Possibly this class is not feature complete since it does not care about multi-relation queries. It should probably use hvad.fieldtranslator.translate() after the first level if it hits the Shared Model.てz

get(self, key)

Returns the translated fieldname for key. If it’s already cached, return it from the cache, otherwise call build()

build(self, key)

Returns the key prefixed by 'master__' if it’s a shared field, otherwise returns the key unchanged.

ValuesMixin

class hvad.manager.ValuesMixin

A mixin class for ValuesQuerySet which implements the functionality needed by TranslationQueryset.values() and TranslationQueryset.values_list().

_strip_master(self, key)

Strips 'master__' from the key if the key starts with that string.

iterator(self)

Iterates over the rows from the superclass iterator and calls _strip_master() on the key if the row is a dictionary.

SkipMasterSelectMixin

class hvad.manager.SkipMasterSelectMixin

A mixin class for specialized querysets such as DateQuerySet and DateTimeQuerySet which forces TranslationQueryset not to add the related lookup on the master field. This is required as those specialized querysets use DISTINCT, and added the related lookup brings along all fields on the Shared Model, breaking the lookup.

TranslationQueryset

class hvad.manager.TranslationQueryset

Any method on this queryset that returns a model instance or a queryset of model instances actually returns a Translations Model which gets combined to behave like a Shared Model. While this manager is on the Shared Model, it is actually a manager for the Translations Model since the model gets switched when this queryset is instantiated from the TranslationManager.

override_classes

A dictionary of django classes to hvad classes to mixin when _clone() is called with an explicit klass argument.

_local_field_names

A list of field names on the Shared Model.

_field_translator

The cached field translator for this manager.

_language_code

The language code of this queryset, or one of the following special values:

  • None: get_language() will be called to get the current language.
  • 'all': no language filtering will be applied, a copy of an instance will be returned for every translation that matched the query.
_language_fallbacks

A tuple of fallbacks used for this queryset, if fallbacks have been activated by fallbacks(), or None otherwise.

A None value in the tuple will be replaced with current language at query evaluation.

_hvad_switch_fields

A tuple of attributes to move from the Translations Model to the Shared Model instance before returning objects to the caller. It is mostly used by extra() so additional values collected by the select argument are available on the final instance.

translations_manager

The (real) manager of the Translations Model.

shared_model

The Shared Model.

field_translator

The field translator for this manager, sets _field_translator if it’s None.

shared_local_field_names

Returns a list of field names on the Shared Model, sets _local_field_names if it’s None.

_translate_args_kwargs(self, *args, **kwargs)

Translates args (Q objects) and kwargs (dictionary of query lookups and values) to be language aware, by prefixing fields on the Shared Model with 'master__'. Uses field_translator for the kwargs and _recurse_q() for the args. Returns a tuple of translated args and translated kwargs.

_translate_fieldnames(self, fieldnames)

Translate a list of fieldnames by prefixing fields on the Shared Model with 'master__' using field_translator. Returns a list of translated fieldnames.

_recurse_q(self, q)

Recursively walks a Q object and translates it’s query lookups to be prefixed by 'master__' if they access a field on Shared Model.

Every Q object has an attribute children which is either a list of other Q objects or a tuple where the key is the query lookup.

This method returns a new Q object.

_find_language_code(self, q)

Searches a Q object for language code lookups. If it finds a child Q object that defines a language code, it returns that language code if it’s not None. Used in get() to ensure a language code is defined.

For more information about Q objects, see _recurse_q().

Returns the language code if one was found or None.

_split_kwargs(self, **kwargs)

Splits keyword arguments into two dictionaries holding the shared and translated fields.

Returns a tuple of dictionaries of shared and translated fields.

_get_class(self, klass)

Given a QuerySet class or subclass, it checks if the class is a subclass of any class in override_classes and if so, returns a new class which mixes the initial class, the class from override_classes and TranslationQueryset. Otherwise returns the class given.

_get_shared_queryset(self)

Returns a clone of this queryset but for the shared model. Does so by creating a QuerySet on shared_model and filtering over this queryset. Returns a queryset for the Shared Model.

_add_language_filter(self)

Apply the language filter to current query. Language is retrieved from _language_code, or get_language() if None. If fallbacks() have been set, apply the additional join as well.

Special value 'all' will prevent any language filter from being applied, resulting in the query considering all translations, possibly returning the same instance mutiple times if several of its translations match. In that case, each instance will be combined with one of the matching translations.

Applied filters include the base language filter on the language_code field, as well as any related model translation set up by select_related().

New in version 0.5.

Applies the related selections to current query. This includes the basic selection of master, any relation specified through select_related() and the translations of any translatable models it navigates through.

language(self, language_code=None)

Specifies a language for this queryset. This sets the _language_code, but no filter are actually applied until _add_language_filter() is called. This allows for query-time resolution of the None value. It is an error to call language() multiple times on the same queryset.

The following special values are accepted:

  • None, or no value: get_language() will be called to get the current language.
  • 'all': no language filtering will be applied, a copy of an instance will be returned for every translation that matched the query, each copy being combined with one of the matching translations.

Returns a queryset.

Note

Support for using language('all') and select_related() on the same queryset is experimental. Please check the generated queries and open an issue if you have any problem. Feedback is appreciated as well.

fallbacks(self, *languages)

New in version 0.6.

Activates fallbacks for this queryset. This sets the _language_fallbacks attribute, but does not apply any join or filtering until _add_language_filter() is called. This allows for query-time resolution of the None values in the list.

The following special cases are accepted:

  • None as a single argument will disable fallbacks on the queryset.
  • An empty argument list will use LANGUAGES setting as a fallback list.
  • A None value a language will be replaced by the current language at query evalution time, by calling get_language()

Returns a queryset.

Note

Using fallbacks and select_related() on the same queryset is not supported and will raise a NotImplementedError.

Note

This feature requires Django 1.6 or newer.

create(self, **kwargs)

Creates a new instance using the kwargs given. If _language_code is not set and language_code is not in kwargs, it uses get_language() to get the current language and injects that into kwargs.

This causes two queries as opposed to the one by the normal queryset.

Returns the newly created (combined) instance.

Note

It is an error to call create with no language_code on a queryset whose _language_code is 'all'. Doing so will raise a ValueError.

bulk_create(self, objs, batch_size=None)

Not implemented yet and unlikely to be due to inherent limitations of multi-table inserts.

update_or_create(self, defaults=None, **kwargs)

Not implemented yet.

get(self, *args, **kwargs)

Gets a single instance from this queryset using the args and kwargs given. The args and kwargs are translated using _translate_args_kwargs().

If a language code is given in the kwargs, it calls language() using the language code provided. If none is given in kwargs, it uses _find_language_code() on the Q objects given in args. If no args were given or they don’t contain a language code, it searches the django.db.models.sql.where.WhereNode objects on the current queryset for language codes. If none was found, it will use the language of this queryset from _language_code, or the current language as returned by get_language() of that is None.

Returns a (combined) instance if one can be found for the filters given, otherwise raises an appropriate exception depending on whether no or multiple objects were found.

Warning

It is an error to pass language_code in a Q object if a select_related() clause was enabled on this queryset. Doing so will raise an AssertionError.

get_or_create(self, **kwargs)

Will try to fetch the translated instance for the kwargs given.

If it can’t find it, it will try to find a shared instance (using _splitkwargs()). If it finds a shared instance, it will create the translated instance. If it does not find a shared instance, it will create both.

Returns a tuple of a (combined) instance and a boolean flag which is False if it found the instance or True if it created either the translated or both instances.

filter(self, *args, **kwargs)

Translates args and kwargs using _translate_args_kwargs() and calls the superclass using the new args and kwargs.

aggregate(self, *args, **kwargs)

Loops through the passed aggregates and translates the fieldnames using _translate_fieldnames() and calls the superclass

latest(self, field_name=None)

Translates the fieldname (if given) using field_translator and calls the superclass.

earliest(self, field_name=None)

New in version 0.4.

Translates the fieldname (if given) using field_translator and calls the superclass.

Only defined if django version is 1.6 or newer.

in_bulk(self, id_list)

New in version 0.4.

Retrieves the objects, building a dict from iterator().

delete(self)

Deletes the Shared Model using _get_shared_queryset().

delete_translations(self)

Deletes the translations (and only the translations) by first breaking their relation to the Shared Model and then calling the delete method on the superclass. This uses two queries.

update(self, **kwargs)

Updates this queryset using kwargs. Calls _split_kwargs() to get two dictionaries holding only the shared or translated fields respectively. If translated fields are given, calls the superclass with the translated fields. If shared fields are given, uses _get_shared_queryset() to update the shared fields.

If both shared and translated fields are updated, two queries are executed, if only one of the two are given, one query is executed.

Returns the count of updated objects, which if both translated and shared fields are given is the sum of the two update calls.

values(self, *fields)

Translates fields using _translate_fieldnames() and calls the superclass.

values_list(self, *fields, **kwargs)

Translates fields using _translate_fieldnames() and calls the superclass.

dates(self, field_name, kind, order='ASC')

Translates fields using _translate_fieldnames() and calls the superclass.

datetimes(self, field_name, *args, **kwargs)

Translates fields using _translate_fieldnames() and calls the superclass.

Only defined if django version is 1.6 or newer.

exclude(self, *args, **kwargs)

Works like filter().

complex_filter(self, filter_obj)

Not really implemented yet, but if filter_obj is an empty dictionary it just returns this queryset, since this is required to get admin to work.

annotate(self, *args, **kwargs)

Not implemented yet.

order_by(self, *field_names)

Translates fields using _translate_fieldnames() and calls the superclass.

reverse(self)

Calls the superclass.

defer(self, *fields)

Not implemented yet.

only(self, *fields)

Not implemented yet.

_clone(self, klass=None, setup=False, **kwargs)

Injects _local_field_names, _field_translator, _language_code, and shared_model into kwargs. If a klass is given, calls _get_class() to get a mixed class if necessary.

Calls the superclass with the new kwargs and klass.

iterator(self)

Iterates using the iterator from the superclass, if the objects yielded have a master, it yields a combined instance, otherwise the instance itself to enable non-cascading deletion.

Interestingly, implementing the combination here also works for get() and __getitem__(). This is because the former uses the latter, which in turn fetches results from an iterator.

TranslationManager

class hvad.manager.TranslationManager

Manager to be used on hvad.models.TranslatableModel.

translations_model

The Translations Model for this manager.

queryset_class

The QuerySet for this manager, used by the language() method. Overwrite to use a custom queryset. Your custom queryset class must inherit TranslationQueryset. Defaults to TranslationQueryset.

fallback_class

The QuerySet for this manager, used by the untranslated() method. Overwrite to use a custom queryset. Defaults to FallbackQueryset.

default_class

The QuerySet for this manager, used by the get_queryset() method and generally any query that does not invoke either language() or untranslated(). Overwrite to use a custom queryset. Defaults to QuerySet.

language(self, language_code=None)

Instanciates a TranslationQueryset from queryset_class and calls TranslationQueryset.language() on that queryset. This type of queryset will filter by language, returning only objects that have a translation in the specified language. Translated fields will be available on the objects, in the specified language.

untranslated(self)

Returns an instance of FallbackQueryset for this manager, or any custom queryset defined by fallback_class. This type of queryset will load translations using fallbacks if current language is not available. It can generate a lot a queries, use with caution.

get_queryset(self)

Returns a vanilla, non-translating queryset for this manager. It uses the default QuerySet or any custom queryset defined by default_class.

Instances returned will not have translated fields, and attempts to access them will result in an exception being raised. See language() and untranslated() to access translated fields.

It is possible to override this behavior by setting default_class to TranslationQueryset, FallbackQueryset or any queryset that has a translation-aware implementation.

contribute_to_class(self, model, name)

Contributes this manager onto the class.

FallbackQueryset

class hvad.manager.FallbackQueryset

Deprecated since version 1.4.

A queryset that can optionally use fallbacks and by default only fetches the Shared Model.

There are actually two underlying implementations, the LegacyFallbackQueryset and the SelfJoinFallbackQueryset. Implementation is chosen at initialization based on the HVAD_LEGACY_FALLBACKS setting. It defaults to False (use SelfJoin) on Django 1.6 and newer, and True (use Legacy) on older versions.

The LegacyFallbackQueryset generates lots of queries as it walks through batches of models, fetches their translations and matches them onto the models.

The SelfJoinFallbackQueryset uses a single self outer join to achieve the same result in only one (complex) query. Performance is good as the number of items per model in the cross-product is limited to the number of languages that Django supports. Implementation digs deeper into Django internals, though.

_translation_fallbacks

List of fallbacks to use (or None).

iterator(self)

If _translation_fallbacks is set, it iterates using the superclass and tries to get the translation using the order of language codes defined in _translation_fallbacks. As soon as it finds a translation for an object, it yields a combined object using that translation. Otherwise yields an uncombined object. Due to the way this works, it can cause a lot of queries and this should be improved if possible.

If no fallbacks are given, it just iterates using the superclass.

use_fallbacks(self, *fallbacks)

Deprecated since version 1.4.

If this method gets called, iterator() will use the fallbacks defined here. None value will be replaced with current language at query evaluation, as returned by get_language(). If not fallbacks are given, FALLBACK_LANGUAGES will be used, with current language prepended.

This method has been superseded by fallbacks() and will be removed when support for Django 1.4 is dropped.

_clone(self, klass=None, setup=False, **kwargs)

Injects translation_fallbacks into kwargs and calls the superclass.

TranslationAwareQueryset

class hvad.manager.TranslationAwareQueryset
_language_code

The language code of this queryset.

_translate_args_kwargs(self, *args, **kwargs)

Calls language() using _language_code as an argument.

Translates args and kwargs into translation aware args and kwargs using hvad.fieldtranslator.translate() by iterating over the kwargs dictionary and translating it’s keys and recursing over the Q objects in args using _recurse_q().

Returns a triple of newargs, newkwargs and extra_filters where newargs and newkwargs are the translated versions of args and kwargs and extra_filters is a Q object to use to filter for the current language.

_recurse_q(self, q)

Recursively translate the keys in the Q object given using hvad.fieldtranslator.translate(). For more information about Q, see TranslationQueryset._recurse_q().

Returns a tuple of q and language_joins where q is the translated Q object and language_joins is a list of extra language join filters to be applied using the current language.

_translate_fieldnames(self, fields)

Calls language() using _language_code as an argument.

Translates the fieldnames given using hvad.fieldtranslator.translate()

Returns a tuple of newfields and extra_filters where newfields is a list of translated fieldnames and extra_filters is a Q object to be used to filter for language joins.

language(self, language_code=None)

Sets the _language_code attribute either to the language given with language_code or by getting the current language from get_language(). Unlike TranslationQueryset.language(), this does not actually filter by the language yet as this happens in _filter_extra().

get(self, *args, **kwargs)

Gets a single object from this queryset by filtering by args and kwargs, which are first translated using _translate_args_kwargs(). Calls _filter_extra() with the extra_filters returned by _translate_args_kwargs() to get a queryset from the superclass and to call that queryset.

Returns an instance of the model of this queryset or raises an appropriate exception when none or multiple objects were found.

filter(self, *args, **kwargs)

Filters the queryset by args and kwargs by translating them using _translate_args_kwargs() and calling _filter_extra() with the extra_filters returned by _translate_args_kwargs().

aggregate(self, *args, **kwargs)

Not implemented yet.

latest(self, field_name=None)

If a fieldname is given, uses hvad.fieldtranslator.translate() to translate that fieldname. Calls _filter_extra() with the extra_filters returned by hvad.fieldtranslator.translate() if it was used, otherwise with an empty Q object.

in_bulk(self, id_list)

Not implemented yet

values(self, *fields)

Calls _translate_fieldnames() to translated the fields. Then calls _filter_extra() with the extra_filters returned by _translate_fieldnames().

values_list(self, *fields, **kwargs)

Calls _translate_fieldnames() to translated the fields. Then calls _filter_extra() with the extra_filters returned by _translate_fieldnames().

dates(self, field_name, kind, order='ASC')

Not implemented yet.

exclude(self, *args, **kwargs)

Not implemented yet.

complex_filter(self, filter_obj)

Not really implemented yet, but if filter_obj is an empty dictionary it just returns this queryset, to make admin work.

annotate(self, *args, **kwargs)

Not implemented yet.

order_by(self, *field_names)

Calls _translate_fieldnames() to translated the fields. Then calls _filter_extra() with the extra_filters returned by _translate_fieldnames().

reverse(self)

Not implemented yet.

defer(self, *fields)

Not implemented yet.

only(self, *fields)

Not implemented yet.

_clone(self, klass=None, setup=False, **kwargs)

Injects _language_code into kwargs and calls the superclass.

_filter_extra(self, extra_filters)

Filters this queryset by the Q object provided in extra_filters and returns a queryset from the superclass, so that the methods that call this method can directely access methods on the superclass to reduce boilerplate code.

Warning

This internal method returns a super() proxy object, be sure to understand the implications before using it.

TranslationAwareManager

class hvad.manager.TranslationAwareManager
get_queryset(self)

Returns an instance of TranslationAwareQueryset.