mirror of
https://github.com/Hopiu/django-modeltranslation.git
synced 2026-04-20 13:10:59 +00:00
Don't leak into current language from .clean_fields()
Django uses .clean_fields() to verify the values of all fields of an
instance, e.g. after the instance has been updated from a form view.
.clean_fields() essentially walks over the fields in the model, reads
the current values, verifies and normalizes them, and writes them
back [1].
With model-translations activated, this can leak values from a fallback
language into the current language of the session, if the value for the
current language has been set to an empty value from a translation aware
application or form.
Example:
- current language is "en"
- fallback languages are "en", "de"
- web form wants to set "title_de" to "Schnapsidee" and leave
"title_en" empty
After the form is submitted, Django calls .clean_fields() which
processes the field "title" first
- reads value of "title" - which gives "Schnapsidee" from
"title_de" by the fallback mechanism of Modeltranslations
- writes this value back to "title", which sets "title_en"
as a side effect.
Bugs have been reported at [2], [3] and [4]
Disable the implicit setting of the translation field from the
translated field ( Rule 2 of [5] ) during .clean_field() processing.
[1] bf77669453/django/db/models/base.py (L1229)
[2] https://github.com/deschler/django-modeltranslation/issues/382
[3] https://github.com/infoportugal/wagtail-modeltranslation/issues/247
[4] https://github.molgen.mpg.de/molgen/mpicms/issues/15
[5] https://django-modeltranslation.readthedocs.io/en/latest/usage.html#rules-for-translated-field-access
This commit is contained in:
parent
0f79d852a5
commit
2c9669efd8
2 changed files with 7 additions and 2 deletions
|
|
@ -314,9 +314,10 @@ class TranslationFieldDescriptor(object):
|
|||
instance.__dict__[self.field.name] = value
|
||||
if isinstance(self.field, fields.related.ForeignKey):
|
||||
instance.__dict__[self.field.get_attname()] = None if value is None else value.pk
|
||||
if getattr(instance, '_mt_init', False):
|
||||
if getattr(instance, '_mt_init', False) or getattr(instance, '_mt_disable', False):
|
||||
# When assignment takes place in model instance constructor, don't set value.
|
||||
# This is essential for only/defer to work, but I think it's sensible anyway.
|
||||
# Setting the localized field may also be disabled by setting _mt_disable.
|
||||
return
|
||||
loc_field_name = build_localized_fieldname(self.field.name, get_language())
|
||||
setattr(instance, loc_field_name, value)
|
||||
|
|
|
|||
|
|
@ -267,7 +267,11 @@ def patch_clean_fields(model):
|
|||
if orig_field_name in exclude:
|
||||
field.save_form_data(self, value, check=False)
|
||||
delattr(self, '_mt_form_pending_clear')
|
||||
old_clean_fields(self, exclude)
|
||||
try:
|
||||
setattr(self, '_mt_disable', True)
|
||||
old_clean_fields(self, exclude)
|
||||
finally:
|
||||
setattr(self, '_mt_disable', False)
|
||||
model.clean_fields = new_clean_fields
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue