- July 4, 2008
- models i18n metaclass translated-content
- 2 (after 2 ratings)
Together with my mentor, Dusty Phillips, I have developed a simple class that dynamically adds two fields to its subclasses.
This is useful in cases when a single piece of content is divided into translatable and non-translatable fields, connected by a 1-to-many relationship.
Since its inception, this snippet has grown into a significantly more powerful solution for translatable content (I use it myself with great joy :). The project is now hosted on github:
It is now possible to define
i18n_common_model attribute in
class Meta section. Here's an example:
class Meta: i18n_common_model = "MyCommonModel"
As you can see, it has to be a string, not the real class, and it is case-sensitive.
class Article(models.Model): author = models.CharField(max_length = 40) class Admin: pass class ArticleI18N(I18NModel): title = models.CharField(max_length = 120) body = models.TextField() class Admin: pass # optionally, you can specify the base class # if it doesn't follow the naming convention: # # class Meta: # i18m_common_model = "Article"
When the ArticleI18N class is created, it automatically gains two new fields.
lang field is a CharField with choices limited to either
django.conf.global_settings.LANGUAGES. The other field is
i18n_common field which is a ForeignKey to Article model.
call the translation model
SomeBaseModelI18N, and the non-translation model SomeBaseModel (i.e., the translation model is called basename+"I18N")
the first convention can be overriden by specifying the base model name using the
Metasection of the
I18N model is a subclass of
Original blog post
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
from django.db.models.base import ModelBase from django.db.models.base import Model from django.db import models from django.conf import settings # Returns class object from a specified module def getclass(classname, modulename): from_module = __import__(modulename, globals(), locals(), classname) return getattr(from_module, classname) class I18NBase(ModelBase): def __new__(cls, name, bases, attrs): try: if I18NModel in bases: attr_meta = attrs.pop('Meta', None) # Find out if `i18n_common_model` is defined in `class Meta`, # and use that. Otherwise, use this class name -4 chars: common_classname = getattr(attr_meta, 'i18n_common_model', name[:-4]) I18NCommonModel = getclass(common_classname, attrs['__module__']) attrs['i18n_common'] = models.ForeignKey(I18NCommonModel) attrs['lang'] = models.CharField(max_length = 5, choices = settings.LANGUAGES) except NameError: pass return ModelBase.__new__(cls, name, bases, attrs) class I18NModel(Model): __metaclass__ = I18NBase class Meta: abstract = True
More like this
- Extended i18n base model by alcinnz 2 years, 7 months ago
- PositionField by jpwatts 7 years, 4 months ago
- Multiple inheritance of newforms and modelforms by simon 7 years, 7 months ago
- Modifying the fields of a third/existing model class by marinho 4 years, 11 months ago
- render_markup filter, specify the markup filter as a string by exogen 8 years, 7 months ago