mirror of
https://github.com/Hopiu/django-modeltranslation.git
synced 2026-05-04 03:24:52 +00:00
More work on the admin integration refactoring. The exclude_languages isn't really thread safe, removed it for now. Handled custom model form fields and exclude options.
This commit is contained in:
parent
6f7704bc57
commit
59c637ba36
2 changed files with 74 additions and 219 deletions
|
|
@ -20,19 +20,16 @@ import modeltranslation.models
|
|||
|
||||
class TranslationBaseModelAdmin(BaseModelAdmin):
|
||||
_orig_was_required = {}
|
||||
exclude_languages = []
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(TranslationBaseModelAdmin, self).__init__(*args, **kwargs)
|
||||
self.trans_opts = translator.get_options_for_model(self.model)
|
||||
# TODO: Handle fields and exclude in form option.
|
||||
if hasattr(self.form, '_meta') and (getattr(self.form._meta, 'fields')
|
||||
or getattr(self.form._meta, 'exclude')):
|
||||
raise ImproperlyConfigured(
|
||||
'The options fields and exclude in a custom ModelForm are '
|
||||
'currently not supported by modeltranslation.')
|
||||
|
||||
def _declared_fieldsets(self):
|
||||
# Take custom modelform fields option into account
|
||||
if not self.fields and hasattr(
|
||||
self.form, '_meta') and self.form._meta.fields:
|
||||
self.fields = self.form._meta.fields
|
||||
if self.fieldsets:
|
||||
return self._patch_fieldsets(self.fieldsets)
|
||||
elif self.fields:
|
||||
|
|
@ -116,47 +113,32 @@ class TranslationBaseModelAdmin(BaseModelAdmin):
|
|||
option = option_new
|
||||
return option
|
||||
|
||||
def _patch_fieldsets(self, fieldsets, exclude_languages=None):
|
||||
def _patch_fieldsets(self, fieldsets):
|
||||
# TODO: Handle nested lists to display multiple fields on same line.
|
||||
if exclude_languages is None:
|
||||
exclude_languages = []
|
||||
if fieldsets:
|
||||
fieldsets_new = list(fieldsets)
|
||||
for (name, dct) in fieldsets:
|
||||
if 'fields' in dct:
|
||||
fields = self.replace_orig_field(dct['fields'])
|
||||
excludes = self.get_translation_field_excludes(
|
||||
exclude_languages)
|
||||
dct['fields'] = [f for f in fields if f not in excludes]
|
||||
#dct['fields'] = self.replace_orig_field(dct['fields'])
|
||||
dct['fields'] = self.replace_orig_field(dct['fields'])
|
||||
fieldsets = fieldsets_new
|
||||
return fieldsets
|
||||
|
||||
def get_translation_field_excludes(self, exclude_languages=None):
|
||||
"""
|
||||
Returns a tuple of translation field names to exclude.
|
||||
|
||||
Defaults to ``self.exclude_languages`` in case ``exclude_languages``
|
||||
parameter isn't set.
|
||||
Returns a tuple of translation field names to exclude base on
|
||||
`exclude_languages` arg.
|
||||
"""
|
||||
if exclude_languages is None:
|
||||
exclude_languages = []
|
||||
excl_languages = []
|
||||
if exclude_languages:
|
||||
excl_languages = exclude_languages
|
||||
else:
|
||||
for lang in self.exclude_languages:
|
||||
# TODO: Not a good place for validation.
|
||||
if lang not in [l[0] for l in settings.LANGUAGES]:
|
||||
raise ImproperlyConfigured(
|
||||
'Language %s not in LANGUAGES setting.' % lang)
|
||||
excl_languages = self.exclude_languages
|
||||
exclude = []
|
||||
for orig_fieldname, translation_fields in \
|
||||
self.trans_opts.localized_fieldnames.iteritems():
|
||||
for tfield in translation_fields:
|
||||
language = tfield.split('_')[-1]
|
||||
if (language in excl_languages
|
||||
and tfield not in exclude):
|
||||
if (language in excl_languages and tfield not in exclude):
|
||||
exclude.append(tfield)
|
||||
return tuple(exclude)
|
||||
|
||||
|
|
@ -164,50 +146,40 @@ class TranslationBaseModelAdmin(BaseModelAdmin):
|
|||
"""
|
||||
Code shared among get_form and get_formset.
|
||||
"""
|
||||
if not self.exclude and hasattr(
|
||||
self.form, '_meta') and self.form._meta.exclude:
|
||||
# Take the custom ModelForm's Meta.exclude into account only if the
|
||||
# ModelAdmin doesn't define its own.
|
||||
kwargs.update({'exclude': getattr(
|
||||
kwargs, 'exclude', tuple()) +
|
||||
tuple(self.replace_orig_field(self.form._meta.exclude))})
|
||||
exclude = kwargs.get('exclude', [])
|
||||
exclude_languages = kwargs.get('exclude_languages', [])
|
||||
# self.exclude_languages = exclude_languages
|
||||
self.exclude = self.replace_orig_field(self.exclude)
|
||||
self.fieldsets = self._patch_fieldsets(
|
||||
self.fieldsets, exclude_languages)
|
||||
#self.fieldsets = self._patch_fieldsets(self.fieldsets)
|
||||
exclude_fields = (
|
||||
self.get_translation_field_excludes(self.exclude_languages) +
|
||||
self._exclude_original_fields(exclude))
|
||||
if self.exclude:
|
||||
exclude_fields = tuple(self.exclude) + tuple(exclude_fields)
|
||||
if exclude_fields:
|
||||
kwargs.update({'exclude': getattr(
|
||||
kwargs, 'exclude', tuple()) + exclude_fields})
|
||||
if kwargs.get('exclude_languages'):
|
||||
del kwargs['exclude_languages']
|
||||
|
||||
return kwargs
|
||||
|
||||
def _do_get_fieldsets_pre_form_or_formset(self, exclude_languages=None):
|
||||
def _do_get_fieldsets_pre_form_or_formset(self):
|
||||
"""
|
||||
Common get_fieldsets code shared among TranslationAdmin and
|
||||
TranslationInlineModelAdmin.
|
||||
"""
|
||||
if exclude_languages is None:
|
||||
exclude_languages = []
|
||||
fields = self.replace_orig_field(self._declared_fieldsets())
|
||||
excludes = self.get_translation_field_excludes(
|
||||
exclude_languages)
|
||||
filtered_fields = [f for f in fields if f not in excludes]
|
||||
return filtered_fields
|
||||
return self.replace_orig_field(self._declared_fieldsets())
|
||||
|
||||
def _do_get_fieldsets_post_form_or_formset(self, request, form, obj=None,
|
||||
exclude_languages=None):
|
||||
def _do_get_fieldsets_post_form_or_formset(self, request, form, obj=None):
|
||||
"""
|
||||
Common get_fieldsets code shared among TranslationAdmin and
|
||||
TranslationInlineModelAdmin.
|
||||
"""
|
||||
if exclude_languages is None:
|
||||
exclude_languages = []
|
||||
base_fields = self.replace_orig_field(form.base_fields.keys())
|
||||
excludes = self.get_translation_field_excludes(
|
||||
exclude_languages)
|
||||
filtered_fields = [f for f in base_fields if f not in excludes]
|
||||
fields = filtered_fields + list(
|
||||
fields = base_fields + list(
|
||||
self.get_readonly_fields(request, obj))
|
||||
return [(None, {'fields': self.replace_orig_field(fields)})]
|
||||
|
||||
|
|
@ -246,29 +218,12 @@ class TranslationAdmin(TranslationBaseModelAdmin, admin.ModelAdmin):
|
|||
kwargs = self._do_get_form_or_formset(**kwargs)
|
||||
return super(TranslationAdmin, self).get_form(request, obj, **kwargs)
|
||||
|
||||
def get_fieldsets(self, request, obj=None, exclude_languages=None):
|
||||
if exclude_languages is None:
|
||||
exclude_languages = []
|
||||
# if self.declared_fieldsets:
|
||||
# fields = self.replace_orig_field(self._declared_fieldsets())
|
||||
# excludes = self.get_translation_field_excludes(
|
||||
# exclude_languages)
|
||||
# filtered_fields = [f for f in fields if f not in excludes]
|
||||
# return filtered_fields
|
||||
# form = self.get_form(request, obj)
|
||||
# base_fields = self.replace_orig_field(form.base_fields.keys())
|
||||
# excludes = self.get_translation_field_excludes(
|
||||
# exclude_languages)
|
||||
# filtered_fields = [f for f in base_fields if f not in excludes]
|
||||
# fields = filtered_fields + list(
|
||||
# self.get_readonly_fields(request, obj))
|
||||
# return [(None, {'fields': self.replace_orig_field(fields)})]
|
||||
def get_fieldsets(self, request, obj=None):
|
||||
if self.declared_fieldsets:
|
||||
return self._do_get_fieldsets_pre_form_or_formset(
|
||||
exclude_languages)
|
||||
return self._do_get_fieldsets_pre_form_or_formset()
|
||||
form = self.get_form(request, obj)
|
||||
return self._do_get_fieldsets_post_form_or_formset(
|
||||
request, form, obj, exclude_languages)
|
||||
request, form, obj)
|
||||
|
||||
def save_model(self, request, obj, form, change):
|
||||
# Rule is: 3. Assigning a value to a translation field of the default
|
||||
|
|
@ -292,15 +247,12 @@ class TranslationInlineModelAdmin(TranslationBaseModelAdmin, InlineModelAdmin):
|
|||
return super(TranslationInlineModelAdmin, self).get_formset(
|
||||
request, obj, **kwargs)
|
||||
|
||||
def get_fieldsets(self, request, obj=None, exclude_languages=None):
|
||||
if exclude_languages is None:
|
||||
exclude_languages = []
|
||||
def get_fieldsets(self, request, obj=None):
|
||||
if self.declared_fieldsets:
|
||||
return self._do_get_fieldsets_pre_form_or_formset(
|
||||
exclude_languages)
|
||||
return self._do_get_fieldsets_pre_form_or_formset()
|
||||
form = self.get_formset(request, obj).form
|
||||
return self._do_get_fieldsets_post_form_or_formset(
|
||||
request, form, obj, exclude_languages)
|
||||
request, form, obj)
|
||||
|
||||
|
||||
class TranslationTabularInline(TranslationInlineModelAdmin,
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
Tests have to be run with modeltranslation.tests.settings:
|
||||
./manage.py test --settings=modeltranslation.tests.settings modeltranslation
|
||||
"""
|
||||
from django import forms
|
||||
from django.conf import settings
|
||||
from django.contrib.admin.sites import AdminSite
|
||||
from django.contrib.auth.models import User
|
||||
|
|
@ -829,7 +830,6 @@ class TranslationAdminTest(ModeltranslationTestBase):
|
|||
pass
|
||||
|
||||
ma = TestModelAdmin(TestModel, self.site)
|
||||
|
||||
self.assertEqual(ma.get_form(request).base_fields.keys(),
|
||||
['title_de', 'title_en', 'text_de', 'text_en',
|
||||
'url_de', 'url_en', 'email_de', 'email_en'])
|
||||
|
|
@ -839,7 +839,6 @@ class TranslationAdminTest(ModeltranslationTestBase):
|
|||
pass
|
||||
|
||||
ma = TestModelAdmin(TestModel, self.site)
|
||||
|
||||
# We expect that the original field is excluded and only the
|
||||
# translation fields are included in fields
|
||||
fields = ['title_de', 'title_en', 'text_de', 'text_en',
|
||||
|
|
@ -849,50 +848,15 @@ class TranslationAdminTest(ModeltranslationTestBase):
|
|||
self.assertEqual(ma.get_fieldsets(request, self.test_obj),
|
||||
[(None, {'fields': fields})])
|
||||
|
||||
def test_fieldsets_with_exclude_languages_override(self):
|
||||
class TestModelAdmin(TranslationAdmin):
|
||||
pass
|
||||
|
||||
ma = TestModelAdmin(TestModel, self.site)
|
||||
|
||||
# We expect that the original field is excluded and only the
|
||||
# translation fields are included in fields
|
||||
exclude_languages = ['en']
|
||||
fields = ['title_de', 'text_de', 'url_de', 'email_de']
|
||||
self.assertEqual(ma.get_fieldsets(request,
|
||||
exclude_languages=exclude_languages),
|
||||
[(None, {'fields': fields})])
|
||||
self.assertEqual(ma.get_fieldsets(request, obj=self.test_obj,
|
||||
exclude_languages=exclude_languages),
|
||||
[(None, {'fields': fields})])
|
||||
|
||||
# Now with option and override
|
||||
class TestModelAdmin(TranslationAdmin):
|
||||
exclude_languages = ['en']
|
||||
|
||||
ma = TestModelAdmin(TestModel, self.site)
|
||||
|
||||
# We expect that the original field is excluded and only the
|
||||
# translation fields are included in fields
|
||||
exclude_languages = ['en']
|
||||
fields = ['title_de', 'text_de', 'url_de', 'email_de']
|
||||
self.assertEqual(ma.get_fieldsets(request,
|
||||
exclude_languages=exclude_languages),
|
||||
[(None, {'fields': fields})])
|
||||
self.assertEqual(ma.get_fieldsets(request, obj=self.test_obj,
|
||||
exclude_languages=exclude_languages),
|
||||
[(None, {'fields': fields})])
|
||||
|
||||
def test_field_arguments(self):
|
||||
class TestModelAdmin(TranslationAdmin):
|
||||
fields = ['title']
|
||||
|
||||
ma = TestModelAdmin(TestModel, self.site)
|
||||
|
||||
self.assertEqual(ma.get_fieldsets(request),
|
||||
[(None, {'fields': ['title_de', 'title_en']})])
|
||||
self.assertEqual(ma.get_fieldsets(request, self.test_obj),
|
||||
[(None, {'fields': ['title_de', 'title_en']})])
|
||||
fields = ['title_de', 'title_en']
|
||||
self.assertEqual(ma.get_form(request).base_fields.keys(), fields)
|
||||
self.assertEqual(ma.get_form(request,
|
||||
self.test_obj).base_fields.keys(), fields)
|
||||
|
||||
def test_field_arguments_restricted_on_form(self):
|
||||
# Using `fields`.
|
||||
|
|
@ -942,127 +906,66 @@ class TranslationAdminTest(ModeltranslationTestBase):
|
|||
self.assertEqual(ma.get_form(request).base_fields.keys(),
|
||||
['title_de', 'title_en'])
|
||||
|
||||
def test_field_arguments_with_exclude_languages(self):
|
||||
# Using `exclude_languages`.
|
||||
def test_field_arguments_restricted_on_custom_form(self):
|
||||
# Using `fields`.
|
||||
class TestModelForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = TestModel
|
||||
fields = ['url', 'email']
|
||||
|
||||
class TestModelAdmin(TranslationAdmin):
|
||||
exclude_languages = ('en',)
|
||||
form = TestModelForm
|
||||
|
||||
ma = TestModelAdmin(TestModel, self.site)
|
||||
# Called directly with no kwargs we expect all english translation
|
||||
# fields to be returned
|
||||
self.assertEqual(ma.get_translation_field_excludes(),
|
||||
('url_en', 'text_en', 'email_en', 'title_en',))
|
||||
|
||||
fields = ['title_de', 'text_de', 'url_de', 'email_de']
|
||||
self.assertEqual(ma.get_form(request).base_fields.keys(), fields)
|
||||
fields = ['url_de', 'url_en', 'email_de', 'email_en']
|
||||
self.assertEqual(ma.get_form(request).base_fields.keys(),
|
||||
fields)
|
||||
self.assertEqual(ma.get_form(request,
|
||||
self.test_obj).base_fields.keys(), fields)
|
||||
|
||||
# Using `exclude_languages` and `fields`.
|
||||
# Using `exclude`.
|
||||
class TestModelForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = TestModel
|
||||
exclude = ['url', 'email']
|
||||
|
||||
class TestModelAdmin(TranslationAdmin):
|
||||
fields = ('title',)
|
||||
exclude_languages = ('en',)
|
||||
form = TestModelForm
|
||||
|
||||
ma = TestModelAdmin(TestModel, self.site)
|
||||
fields = ['title_de']
|
||||
self.assertEqual(ma.get_form(request).base_fields.keys(), fields)
|
||||
fields = ['title_de', 'title_en', 'text_de', 'text_en']
|
||||
self.assertEqual(ma.get_form(request).base_fields.keys(),
|
||||
fields)
|
||||
self.assertEqual(ma.get_form(request,
|
||||
self.test_obj).base_fields.keys(), fields)
|
||||
|
||||
# Using `exclude_languages` and `exclude`.
|
||||
# If both, the custom form an the ModelAdmin define an `exclude`
|
||||
# option, the ModelAdmin wins. This is Django behaviour.
|
||||
class TestModelAdmin(TranslationAdmin):
|
||||
fields = ('title',)
|
||||
exclude_languages = ('en',)
|
||||
form = TestModelForm
|
||||
exclude = ['url']
|
||||
|
||||
ma = TestModelAdmin(TestModel, self.site)
|
||||
fields = ['title_de']
|
||||
self.assertEqual(ma.get_form(request).base_fields.keys(), fields)
|
||||
fields = ['title_de', 'title_en', 'text_de', 'text_en', 'email_de',
|
||||
'email_en']
|
||||
self.assertEqual(ma.get_form(request).base_fields.keys(),
|
||||
fields)
|
||||
self.assertEqual(ma.get_form(request,
|
||||
self.test_obj).base_fields.keys(), fields)
|
||||
|
||||
# Using `exclude_languages` and `fieldsets`.
|
||||
# Same for `fields`.
|
||||
class TestModelForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = TestModel
|
||||
fields = ['text', 'title']
|
||||
|
||||
class TestModelAdmin(TranslationAdmin):
|
||||
fieldsets = [(None, {'fields': ['title']})]
|
||||
exclude_languages = ('en',)
|
||||
form = TestModelForm
|
||||
fields = ['email']
|
||||
|
||||
ma = TestModelAdmin(TestModel, self.site)
|
||||
fields = ['title_de']
|
||||
self.assertEqual(ma.get_form(request).base_fields.keys(), fields)
|
||||
self.assertEqual(ma.get_form(request,
|
||||
self.test_obj).base_fields.keys(), fields)
|
||||
|
||||
# Using `exclude_languages` and `exclude` and `fields`.
|
||||
class TestModelAdmin(TranslationAdmin):
|
||||
fields = ('title', 'text',)
|
||||
exclude = ('text',)
|
||||
exclude_languages = ('en',)
|
||||
|
||||
ma = TestModelAdmin(TestModel, self.site)
|
||||
fields = ['title_de']
|
||||
self.assertEqual(ma.get_form(request).base_fields.keys(), fields)
|
||||
self.assertEqual(ma.get_form(request,
|
||||
self.test_obj).base_fields.keys(), fields)
|
||||
|
||||
# Using `exclude_languages` and `fields` and `fieldsets`.
|
||||
# The `fieldsets` option is supposed to win over `fields`,
|
||||
# `exclude` is still honoured.
|
||||
class TestModelAdmin(TranslationAdmin):
|
||||
fieldsets = [(None, {'fields': ['url', 'text']})]
|
||||
exclude = ('text',)
|
||||
exclude_languages = ('en',)
|
||||
|
||||
ma = TestModelAdmin(TestModel, self.site)
|
||||
fields = ['url_de']
|
||||
self.assertEqual(ma.get_form(request).base_fields.keys(), fields)
|
||||
self.assertEqual(ma.get_form(request,
|
||||
self.test_obj).base_fields.keys(), fields)
|
||||
|
||||
# Using `exclude_languages` and `exclude` and `fieldsets`.
|
||||
# The `exclude` option is honoured.
|
||||
class TestModelAdmin(TranslationAdmin):
|
||||
fieldsets = [(None, {'fields': ['url']})]
|
||||
exclude = ('url',)
|
||||
exclude_languages = ('en',)
|
||||
|
||||
ma = TestModelAdmin(TestModel, self.site)
|
||||
fields = []
|
||||
self.assertEqual(ma.get_form(request).base_fields.keys(), fields)
|
||||
self.assertEqual(ma.get_form(request,
|
||||
self.test_obj).base_fields.keys(), fields)
|
||||
|
||||
# Using `exclude_languages` and `exclude` and `fields` and `fieldsets`.
|
||||
# `fieldsets` is supposed to win in this case.
|
||||
class TestModelAdmin(TranslationAdmin):
|
||||
fieldsets = [(None, {'fields': ['title', 'url']})]
|
||||
fields = ('title', 'text',)
|
||||
exclude = ('url',)
|
||||
exclude_languages = ('en',)
|
||||
|
||||
ma = TestModelAdmin(TestModel, self.site)
|
||||
fields = ['title_de']
|
||||
self.assertEqual(ma.get_form(request).base_fields.keys(), fields)
|
||||
self.assertEqual(ma.get_form(request,
|
||||
self.test_obj).base_fields.keys(), fields)
|
||||
|
||||
# Using `exclude_languages` and `exclude` with a translation field.
|
||||
class TestModelAdmin(TranslationAdmin):
|
||||
exclude = ('email_de',)
|
||||
exclude_languages = ('en',)
|
||||
|
||||
ma = TestModelAdmin(TestModel, self.site)
|
||||
fields = ['title_de', 'text_de', 'url_de']
|
||||
self.assertEqual(ma.get_form(request).base_fields.keys(), fields)
|
||||
self.assertEqual(ma.get_form(request,
|
||||
self.test_obj).base_fields.keys(), fields)
|
||||
|
||||
# Using `exclude_languages` and `fieldsets` with a translation field.
|
||||
# `exclude_languages` is supposed to win in this case.
|
||||
class TestModelAdmin(TranslationAdmin):
|
||||
fieldsets = [(None, {'fields': ['title_en', 'url']})]
|
||||
exclude_languages = ('en',)
|
||||
|
||||
ma = TestModelAdmin(TestModel, self.site)
|
||||
fields = ['url_de']
|
||||
self.assertEqual(ma.get_form(request).base_fields.keys(), fields)
|
||||
fields = ['email_de', 'email_en']
|
||||
self.assertEqual(ma.get_form(request).base_fields.keys(),
|
||||
fields)
|
||||
self.assertEqual(ma.get_form(request,
|
||||
self.test_obj).base_fields.keys(), fields)
|
||||
|
|
|
|||
Loading…
Reference in a new issue