Unverified Commit 619e7294 authored by Joost Rijneveld's avatar Joost Rijneveld
Browse files

Support translated field names in ModelAdmin

parent f812672d
from django.contrib import admin
from django.db import models
from django.db.models.fields.related import RelatedField
from django.conf import settings
......@@ -51,27 +52,75 @@ def _i18n_attr_accessor(attr):
class ModelTranslateMeta(models.base.ModelBase):
def __new__(cls, name, bases, dct):
field_i18n = {'default': {}, 'fields': {}}
for attr, field in list(dct.items()):
if isinstance(field, MultilingualField):
# ForeignKey, OneToOneField and ManyToManyField do not have
# a verbose name as first positional argument.
# But those are not translatable (see above).
if len(field.args) > 0:
verbose_base = ('args', field.args[0])
if not isinstance(field, MultilingualField):
continue
# ForeignKey, OneToOneField and ManyToManyField do not have
# a verbose name as first positional argument.
# But those are not translatable (see above).
if len(field.args) > 0:
verbose_base = ('args', field.args[0])
else:
verbose_base = ('kwargs', field.kwargs.get('verbose_name',
attr))
fields = []
for lang in settings.LANGUAGES:
attr_i18n = I18N_FIELD_FORMAT.format(attr, lang[0])
verbose_name = '{} ({})'.format(verbose_base[1],
lang[0].upper())
if verbose_base[0] == 'args':
field.args = (verbose_name,) + field.args[1:]
else:
verbose_base = ('kwargs', field.kwargs.get('verbose_name',
attr))
for lang in settings.LANGUAGES:
attr_i18n = I18N_FIELD_FORMAT.format(attr, lang[0])
verbose_name = '{} ({})'.format(verbose_base[1],
lang[0].upper())
if verbose_base[0] == 'args':
field.args = (verbose_name,) + field.args[1:]
else:
field.kwargs['verbose_name'] = verbose_name
if attr_i18n in dct:
raise FieldError("Explicit field {} is shadowed "
"by TranslateMeta.".format(attr_i18n))
dct[attr_i18n] = field.cls(*field.args, **field.kwargs)
dct[attr] = property(_i18n_attr_accessor(attr))
return super(ModelTranslateMeta, cls).__new__(cls, name, bases, dct)
field.kwargs['verbose_name'] = verbose_name
if attr_i18n in dct:
raise FieldError("Explicit field {} is shadowed "
"by TranslateMeta.".format(attr_i18n))
dct[attr_i18n] = field.cls(*field.args, **field.kwargs)
fields.append(attr_i18n)
dct[attr] = property(_i18n_attr_accessor(attr))
default = I18N_FIELD_FORMAT.format(attr, settings.LANGUAGE_CODE)
if default not in dct:
raise ImproperlyConfigured("LANGUAGE_CODE not in LANGUAGES.")
field_i18n['default'][attr] = default
field_i18n['fields'][attr] = fields
model = super(ModelTranslateMeta, cls).__new__(cls, name, bases, dct)
if hasattr(model._meta, '_field_i18n'):
raise FieldError("TranslateMeta map already exists!")
model._meta._field_i18n = field_i18n
return model
class TranslatedModelAdmin(admin.ModelAdmin):
"""This class should be used when the ModelAdmin is used with a
translated model and one refers to such a field in the `fields`
or `fieldsets` attributes, or in `prepopulated_fields`.
This works because admin.ModelAdmin has an empty metaclass; we can hook
in to __init__ and modify the attributes when model is known."""
def __init__(self, model, admin_site):
for key, fields in list(type(self).prepopulated_fields.items()):
# Replace translated fields in `fields`
fields = tuple(model._meta._field_i18n['default'].get(field, field)
for field in fields)
# ..and in `key`
del type(self).prepopulated_fields[key]
key = model._meta._field_i18n['default'].get(key, key)
type(self).prepopulated_fields[key] = fields
def trans_fields(fields):
if fields is None:
return None
fields = [model._meta._field_i18n['fields']
.get(field, (field, )) for field in fields]
return tuple(field for fieldset in fields for field in fieldset)
# In fields, we replace a translated field by all resulting fields.
type(self).fields = trans_fields(type(self).fields)
type(self).exclude = trans_fields(type(self).exclude)
if type(self).fieldsets is not None:
for fieldset in type(self).fieldsets:
fieldset[1]['fields'] = trans_fields(fieldset[1]['fields'])
super(TranslatedModelAdmin, self).__init__(model, admin_site)
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment