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
The implementation is loosely based on RelatedFieldWidgetWrapper from contrib.admin, but uses a bit more Python magic; tested only with TextInput and Textarea widgets and their admin counterparts, but with a bit of luck should work with other widgets too.
Overriden admin widgets of CharFields and TextFields and patched forms.CharField for nullable fields, so undefined translations don't get filled with empty strings when an admin form is saved (thus becoming defined in the case of a nullable field).