Example #1
0
    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
Example #3
0
    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)