Defining models with django-hvad is done by inheriting TranslatableModel. Model definition works like in regular Django, with the following additional features:
A full example of a model with translations:
from django.db import models
from hvad.models import TranslatableModel, TranslatedFields
class TVSeries(TranslatableModel):
distributor = models.CharField(max_length=255)
translations = TranslatedFields(
title = models.CharField(max_length=100),
subtitle = models.CharField(max_length=255),
released = models.DateTimeField(),
meta={'unique_together': [('title', 'subtitle')]},
)
Note
The Meta class of the model may not use the translatable fields in those options:
Prepares a new translation for this instance for the language specified.
Warning
This does not check if this language already exists in the database and assumes it does not! If it already exists and you try to save this instance, it will break!
Note
This method does not perform any database queries.
Returns the value of the field specified by name if it’s available on this instance in the currently cached language. It does not try to get the value from the database. Returns the value specified in default if no translation was cached on this instance or the translation does not have a value for this field.
This method is useful to safely get a value in methods such as __unicode__().
Note
This method never performs any database queries.
Example usage:
class MyModel(TranslatableModel):
translations = TranslatedFields(
name = models.CharField(max_length=255)
)
def __unicode__(self):
return self.safe_translation_getter('name', 'MyMode: %s' % self.pk)
Changed in version 0.4.
Tries to get the value of the field specified by name using safe_translation_getter(). If this fails, tries to load a translation from the database. If none exists, returns the value specified in default.
This method is useful to get a value in methods such as __unicode__().
Note
This method may perform a database query.
Example usage:
class MyModel(TranslatableModel):
translations = TranslatedFields(
name = models.CharField(max_length=255)
)
def __unicode__(self):
return self.lazy_translation_getter('name', 'MyMode: %s' % self.pk)
Returns a list of available language codes for this instance.
Note
This method runs a database query to fetch the available languages, unless they were prefetched before (if the instance was retrived with a call to prefetch_related('translations')).
Foreign keys pointing to a Translated Model always point to the Shared Model. It is currently not possible to have a foreign key to a Translations Model.
Please note that select_related() used on a foreign key pointing to a Translated Model does not span to its Translations Model and therefore accessing a translated field over the relation causes an extra query.
If you wish to filter over a translated field over the relation from a Normal Model you have to use get_translation_aware_manager() to get a manager that allows you to do so. That function takes your model class as argument and returns a manager that works with translated fields on related models.
Changed in version 0.5.
Vanilla managers, using vanilla querysets can be used with translatable models. However, they will not have access to translations or translatable fields. Also, such a vanilla manager cannot server as a default manager for the model. The default manager must be translation aware.
To have full access to translations and translatable fields, custom managers must inherit TranslationManager and custom querysets must inherit either TranslationQueryset (enabling the use of language()) or FallbackQueryset (enabling the use of use_fallbacks()). Both are described in the dedicated section.
Once you have a custom queryset, you can use it to override the default ones in your manager. This is where it is more complex than a regular manager: TranslationManager uses three types of queryset, that can be overriden independently:
As a convenience, it is possible to override the queryset at manager instanciation, avoiding the need to subclass the manager:
class TVSeriesTranslationQueryset(TranslationQueryset):
def is_public_domain(self):
threshold = datetime.now() - timedelta(days=365*70)
return self.filter(released__gt=threshold)
class TVSeries(TranslatableModel):
# ... (see full definition in previous example)
objects = TranslationManager(queryset_class=TVSeriesTranslationQueryset)
More on querysets in the dedicated section.
New in version 0.5.
Abstract models can be used normally with hvad. Untranslatable fields of the base models will remain untranslatable, while translatable fields will be translatable on the concrete model as well:
class Place(TranslatableModel):
coordinates = models.CharField(max_length=64)
translations = TranslatedFields(
name = models.CharField(max_length=255),
)
class Meta:
abstract = True
class Restaurant(Place):
score = models.PositiveIntegerField()
translations = TranslatedFields() # see note below
Note
The concrete models must have a TranslatedFields instance as one of their attributes. This is required because this attribute will be used to access the translations. It can be empty.
New in version 0.4.
Proxy models can be used normally with hvad, with the following restrictions:
The __init__ method and signals for the concrete model will still be called.
Next, we will detail the translation-aware querysets provided by hvad.