def patch_translation_field(self, db_field, field, **kwargs): if db_field.name in self.trans_opts.fields: if field.required: field.required = False field.blank = True self._orig_was_required['%s.%s' % (db_field.model._meta, db_field.name)] = True # For every localized field copy the widget from the original field # and add a css class to identify a modeltranslation widget. try: orig_field = db_field.translated_field except AttributeError: pass else: orig_formfield = self.formfield_for_dbfield(orig_field, **kwargs) field.widget = deepcopy(orig_formfield.widget) # if any widget attrs are defined on the form they should be copied try: field.widget = deepcopy(self.form._meta.widgets[orig_field.name]) except (AttributeError, TypeError, KeyError): pass # field.widget = deepcopy(orig_formfield.widget) if orig_field.name in self.both_empty_values_fields: from modeltranslation.forms import NullableField, NullCharField form_class = field.__class__ if issubclass(form_class, NullCharField): # NullableField don't work with NullCharField form_class.__bases__ = tuple( b for b in form_class.__bases__ if b != NullCharField) field.__class__ = type( 'Nullable%s' % form_class.__name__, (NullableField, form_class), {}) if ( ( db_field.empty_value == 'both' or orig_field.name in self.both_empty_values_fields ) and isinstance(field.widget, (forms.TextInput, forms.Textarea)) ): field.widget = ClearableWidgetWrapper(field.widget) css_classes = field.widget.attrs.get('class', '').split(' ') css_classes.append('mt') # Add localized fieldname css class css_classes.append(build_css_class(db_field.name, 'mt-field')) # Add mt-bidi css class if language is bidirectional if(get_language_bidi(db_field.language)): css_classes.append('mt-bidi') if db_field.language == mt_settings.DEFAULT_LANGUAGE: # Add another css class to identify a default modeltranslation widget css_classes.append('mt-default') if (orig_formfield.required or self._orig_was_required.get( '%s.%s' % (orig_field.model._meta, orig_field.name))): # In case the original form field was required, make the # default translation field required instead. orig_formfield.required = False orig_formfield.blank = True field.required = True field.blank = False # Hide clearable widget for required fields if isinstance(field.widget, ClearableWidgetWrapper): field.widget = field.widget.widget field.widget.attrs['class'] = ' '.join(css_classes)
def formfield(self, *args, **kwargs): """ Returns proper formfield, according to empty_values setting (only for ``forms.CharField`` subclasses). There are 3 different formfields: - CharField that stores all empty values as empty strings; - NullCharField that stores all empty values as None (Null); - NullableField that can store both None and empty string. By default, if no empty_values was specified in model's translation options, NullCharField would be used if the original field is nullable, CharField otherwise. This can be overridden by setting empty_values to '' or None. Setting 'both' will result in NullableField being used. Textual widgets (subclassing ``TextInput`` or ``Textarea``) used for nullable fields are enriched with a clear checkbox, allowing ``None`` values to be preserved rather than saved as empty strings. The ``forms.CharField`` somewhat surprising behaviour is documented as a "won't fix": https://code.djangoproject.com/ticket/9590. """ formfield = super(TranslationField, self).formfield(*args, **kwargs) if isinstance(formfield, forms.CharField): if self.empty_value is None: from modeltranslation.forms import NullCharField form_class = formfield.__class__ kwargs['form_class'] = type('Null%s' % form_class.__name__, (NullCharField, form_class), {}) formfield = super(TranslationField, self).formfield(*args, **kwargs) elif self.empty_value == 'both': from modeltranslation.forms import NullableField form_class = formfield.__class__ kwargs['form_class'] = type('Nullable%s' % form_class.__name__, (NullableField, form_class), {}) formfield = super(TranslationField, self).formfield(*args, **kwargs) if isinstance(formfield.widget, (forms.TextInput, forms.Textarea)): formfield.widget = ClearableWidgetWrapper(formfield.widget) return formfield
def formfield(self, *args, **kwargs): """ If the original field is nullable and uses ``forms.CharField`` subclass as its form input, we patch the form field, so it doesn't cast ``None`` to anything. The ``forms.CharField`` somewhat surprising behaviour is documented as a "won't fix": https://code.djangoproject.com/ticket/9590. Textual widgets (subclassing ``TextInput`` or ``Textarea``) used for nullable fields are enriched with a clear checkbox, allowing ``None`` values to be preserved rather than saved as empty strings. """ formfield = super(TranslationField, self).formfield(*args, **kwargs) if self.translated_field.null: if isinstance(formfield, forms.CharField): from modeltranslation.forms import NullableField form_class = formfield.__class__ kwargs['form_class'] = type( 'Nullable%s' % form_class.__name__, (NullableField, form_class), {}) formfield = super(TranslationField, self).formfield(*args, **kwargs) if isinstance(formfield.widget, (forms.TextInput, forms.Textarea)): formfield.widget = ClearableWidgetWrapper(formfield.widget) return formfield
def patch_translation_field(self, db_field, field, **kwargs): if db_field.name in self.trans_opts.fields: if field.required: field.required = False field.blank = True self._orig_was_required['%s.%s' % (db_field.model._meta, db_field.name)] = True # For every localized field copy the widget from the original field # and add a css class to identify a modeltranslation widget. try: orig_field = db_field.translated_field except AttributeError: pass else: orig_formfield = self.formfield_for_dbfield(orig_field, **kwargs) field.widget = deepcopy(orig_formfield.widget) if orig_field.null and isinstance(field.widget, (forms.TextInput, forms.Textarea)): field.widget = ClearableWidgetWrapper(field.widget) css_classes = field.widget.attrs.get('class', '').split(' ') css_classes.append('mt') # Add localized fieldname css class css_classes.append(build_css_class(db_field.name, 'mt-field')) if db_field.language == DEFAULT_LANGUAGE: # Add another css class to identify a default modeltranslation # widget. css_classes.append('mt-default') if (orig_formfield.required or self._orig_was_required.get( '%s.%s' % (orig_field.model._meta, orig_field.name))): # In case the original form field was required, make the # default translation field required instead. orig_formfield.required = False orig_formfield.blank = True field.required = True field.blank = False field.widget.attrs['class'] = ' '.join(css_classes)