from django.db.models.base import ModelBase, Model from django.db.models import Field, Q from django.db import models from django.conf import settings from django.utils.translation import get_language # 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['_fields'] = ('lang',) + tuple(attr for attr, value in attrs.items() if isinstance(value, Field)) attrs['i18n_common'] = models.ForeignKey(I18NCommonModel, related_name='translations') attrs['lang'] = models.CharField(max_length = 5, choices = settings.LANGUAGES) except NameError: I18NCommonModel = None ret = ModelBase.__new__(cls, name, bases, attrs) if I18NCommonModel: I18NCommonModel.I18N = ret return ret class I18NModel(Model): __metaclass__ = I18NBase class Meta: abstract = True class I18NMixin(Model): """To be added as an (optionally) additional superclass of models with associated I18N models.""" class Meta(object): abstract = True def trans(self): """Returns the translation object for the user's language.""" qs = self.translations.filter(lang=get_language()) if not qs.exists(): qs = self.translations.filter(lang=get_language().split('-')[0]) return qs.get() _ = property(trans) def i18nQ(**kwargs): def q(**kwargs): return Q(**{'translations__'+key : val for key, val in kwargs.items()}) _ = get_language() return (q(lang=_) | q(lang=_.split('-')[0])) & q(**kwargs) from django.contrib.admin import TabularInline def I18NFieldset(i18nModel): class inner(TabularInline): model = i18nModel fields = i18nModel._fields extra = 1 return inner