Using forms with django-translated-fields

510 views Asked by At

Please take a look at this issue:

How do I use ModelForm with django-translated-fields?

Do you have any solution?

In short, I'm trying to convert Speedy Net from using django-modeltranslation to django-translated-fields. I defined the models and forms and everything works in English, but in another language (Hebrew) I have a problem that the form fields are defined in English instead of Hebrew (the current language). What did I do wrong and how do I define the form to work in the current language? (the fields defined by TranslatedField in the model should be visible only with the current language in the form SpeedyMatchProfileActivationForm).

I want to clarify that the desired definition is not as above. The desired definition is to use the current language in the form and not always English. Using English when the current language is not English is a bug.

You can see the code here:

tree

forms.py

models.py

The problem right now is with the class SpeedyMatchProfileActivationForm (defined in forms.py). I think it is mainly because the class is defined before get_language() returns anything. But when the class was defined with django-modeltranslation (for example in branch staging), it worked.

By the way, one of the reasons I want to switch to django-translated-fields is because it defines only 2 (the number of languages) fields in the database, and django-modeltranslation defines 3 fields - one of them (the main field without any language) seems to me not necessary at all. Take a look at: Remove original language field on migrations

class SpeedyMatchProfileActivationForm is defined now (with django-translated-fields, link):

class SpeedyMatchProfileActivationForm(forms.ModelForm):
    validators = {
        'height': [speedy_match_accounts_validators.validate_height],
        'smoking_status': [speedy_match_accounts_validators.validate_smoking_status],
        'marital_status': [speedy_match_accounts_validators.validate_marital_status],
        to_attribute(name='profile_description'): [speedy_match_accounts_validators.validate_profile_description],
        to_attribute(name='city'): [speedy_match_accounts_validators.validate_city],
        to_attribute(name='children'): [speedy_match_accounts_validators.validate_children],
        to_attribute(name='more_children'): [speedy_match_accounts_validators.validate_more_children],
        to_attribute(name='match_description'): [speedy_match_accounts_validators.validate_match_description],
        'gender_to_match': [speedy_match_accounts_validators.validate_gender_to_match],
        'min_age_match': [speedy_match_accounts_validators.validate_min_age_match],
        'max_age_match': [speedy_match_accounts_validators.validate_max_age_match],
        'diet_match': [speedy_match_accounts_validators.validate_diet_match],
        'smoking_status_match': [speedy_match_accounts_validators.validate_smoking_status_match],
        'marital_status_match': [speedy_match_accounts_validators.validate_marital_status_match],
    }
    diet = forms.ChoiceField(choices=User.DIET_VALID_CHOICES, widget=forms.RadioSelect(), label=_('My diet'), validators=[speedy_match_accounts_validators.validate_diet])
    photo = forms.ImageField(required=False, widget=CustomPhotoWidget, label=_('Add profile picture'))

    class Meta:
        model = SpeedyMatchSiteProfile
        fields = ('photo', to_attribute(name='profile_description'), to_attribute(name='city'), 'height', to_attribute(name='children'), to_attribute(name='more_children'), 'diet', 'smoking_status', 'marital_status', 'gender_to_match', to_attribute(name='match_description'), 'min_age_match', 'max_age_match', 'diet_match', 'smoking_status_match', 'marital_status_match')
        widgets = {
            'smoking_status': forms.RadioSelect(),
            'marital_status': forms.RadioSelect(),
            to_attribute(name='profile_description'): forms.Textarea(attrs={'rows': 3, 'cols': 25}),
            to_attribute(name='city'): forms.TextInput(),
            to_attribute(name='children'): forms.TextInput(),
            to_attribute(name='more_children'): forms.TextInput(),
            to_attribute(name='match_description'): forms.Textarea(attrs={'rows': 3, 'cols': 25}),
            'diet_match': CustomJsonWidget(choices=User.DIET_VALID_CHOICES),
            'smoking_status_match': CustomJsonWidget(choices=SpeedyMatchSiteProfile.SMOKING_STATUS_VALID_CHOICES),
            'marital_status_match': CustomJsonWidget(choices=SpeedyMatchSiteProfile.MARITAL_STATUS_VALID_CHOICES),
        }

It was previously defined (with django-modeltranslation, link):

class SpeedyMatchProfileActivationForm(TranslationModelForm):
    validators = {
        'height': [speedy_match_accounts_validators.validate_height],
        'min_age_match': [speedy_match_accounts_validators.validate_min_age_match],
        'max_age_match': [speedy_match_accounts_validators.validate_max_age_match],
        'smoking_status': [speedy_match_accounts_validators.validate_smoking_status],
        'city': [speedy_match_accounts_validators.validate_city],
        'marital_status': [speedy_match_accounts_validators.validate_marital_status],
        'children': [speedy_match_accounts_validators.validate_children],
        'more_children': [speedy_match_accounts_validators.validate_more_children],
        'profile_description': [speedy_match_accounts_validators.validate_profile_description],
        'match_description': [speedy_match_accounts_validators.validate_match_description],
        'gender_to_match': [speedy_match_accounts_validators.validate_gender_to_match],
        'diet_match': [speedy_match_accounts_validators.validate_diet_match],
        'smoking_status_match': [speedy_match_accounts_validators.validate_smoking_status_match],
        'marital_status_match': [speedy_match_accounts_validators.validate_marital_status_match],
    }
    diet = forms.ChoiceField(choices=User.DIET_VALID_CHOICES, widget=forms.RadioSelect(), label=_('My diet'), validators=[speedy_match_accounts_validators.validate_diet])
    photo = forms.ImageField(required=False, widget=CustomPhotoWidget, label=_('Add profile picture'))

    class Meta:
        model = SpeedyMatchSiteProfile
        fields = ('photo', 'profile_description', 'city', 'height', 'children', 'more_children', 'diet', 'smoking_status', 'marital_status', 'gender_to_match', 'match_description', 'min_age_match', 'max_age_match', 'diet_match', 'smoking_status_match', 'marital_status_match')
        widgets = {
            'profile_description': forms.Textarea(attrs={'rows': 3, 'cols': 25}),
            'children': forms.TextInput(),
            'more_children': forms.TextInput(),
            'smoking_status': forms.RadioSelect(),
            'marital_status': forms.RadioSelect(),
            'match_description': forms.Textarea(attrs={'rows': 3, 'cols': 25}),
            'diet_match': CustomJsonWidget(choices=User.DIET_VALID_CHOICES),
            'smoking_status_match': CustomJsonWidget(choices=SpeedyMatchSiteProfile.SMOKING_STATUS_VALID_CHOICES),
            'marital_status_match': CustomJsonWidget(choices=SpeedyMatchSiteProfile.MARITAL_STATUS_VALID_CHOICES),
        }

Thanks!

1

There are 1 answers

0
Uri On BEST ANSWER

I found a solution. It's not the optimal solution but it works. I added the fields in all languages to the form. The fields we don't need are already removed in the __init__ method.

class SpeedyMatchProfileActivationForm(forms.ModelForm):
    validators = {
        'height': [speedy_match_accounts_validators.validate_height],
        'smoking_status': [speedy_match_accounts_validators.validate_smoking_status],
        'marital_status': [speedy_match_accounts_validators.validate_marital_status],
        **{to_attribute(name='profile_description', language_code=language_code): [speedy_match_accounts_validators.validate_profile_description] for language_code, language_name in django_settings.LANGUAGES},
        **{to_attribute(name='city', language_code=language_code): [speedy_match_accounts_validators.validate_city] for language_code, language_name in django_settings.LANGUAGES},
        **{to_attribute(name='children', language_code=language_code): [speedy_match_accounts_validators.validate_children] for language_code, language_name in django_settings.LANGUAGES},
        **{to_attribute(name='more_children', language_code=language_code): [speedy_match_accounts_validators.validate_more_children] for language_code, language_name in django_settings.LANGUAGES},
        **{to_attribute(name='match_description', language_code=language_code): [speedy_match_accounts_validators.validate_match_description] for language_code, language_name in django_settings.LANGUAGES},
        'gender_to_match': [speedy_match_accounts_validators.validate_gender_to_match],
        'min_age_match': [speedy_match_accounts_validators.validate_min_age_match],
        'max_age_match': [speedy_match_accounts_validators.validate_max_age_match],
        'diet_match': [speedy_match_accounts_validators.validate_diet_match],
        'smoking_status_match': [speedy_match_accounts_validators.validate_smoking_status_match],
        'marital_status_match': [speedy_match_accounts_validators.validate_marital_status_match],
    }
    diet = forms.ChoiceField(choices=User.DIET_VALID_CHOICES, widget=forms.RadioSelect(), label=_('My diet'), validators=[speedy_match_accounts_validators.validate_diet])
    photo = forms.ImageField(required=False, widget=CustomPhotoWidget, label=_('Add profile picture'))

    class Meta:
        model = SpeedyMatchSiteProfile
        fields = (
            'photo',
            *(to_attribute(name='profile_description', language_code=language_code) for language_code, language_name in django_settings.LANGUAGES),
            *(to_attribute(name='city', language_code=language_code) for language_code, language_name in django_settings.LANGUAGES),
            'height',
            *(to_attribute(name='children', language_code=language_code) for language_code, language_name in django_settings.LANGUAGES),
            *(to_attribute(name='more_children', language_code=language_code) for language_code, language_name in django_settings.LANGUAGES),
            'diet',
            'smoking_status',
            'marital_status',
            'gender_to_match',
            *(to_attribute(name='match_description', language_code=language_code) for language_code, language_name in django_settings.LANGUAGES),
            'min_age_match',
            'max_age_match',
            'diet_match',
            'smoking_status_match',
            'marital_status_match',
        )
        widgets = {
            'smoking_status': forms.RadioSelect(),
            'marital_status': forms.RadioSelect(),
            **{to_attribute(name='profile_description', language_code=language_code): forms.Textarea(attrs={'rows': 3, 'cols': 25}) for language_code, language_name in django_settings.LANGUAGES},
            **{to_attribute(name='city', language_code=language_code): forms.TextInput() for language_code, language_name in django_settings.LANGUAGES},
            **{to_attribute(name='children', language_code=language_code): forms.TextInput() for language_code, language_name in django_settings.LANGUAGES},
            **{to_attribute(name='more_children', language_code=language_code): forms.TextInput() for language_code, language_name in django_settings.LANGUAGES},
            **{to_attribute(name='match_description', language_code=language_code): forms.Textarea(attrs={'rows': 3, 'cols': 25}) for language_code, language_name in django_settings.LANGUAGES},
            'diet_match': CustomJsonWidget(choices=User.DIET_VALID_CHOICES),
            'smoking_status_match': CustomJsonWidget(choices=SpeedyMatchSiteProfile.SMOKING_STATUS_VALID_CHOICES),
            'marital_status_match': CustomJsonWidget(choices=SpeedyMatchSiteProfile.MARITAL_STATUS_VALID_CHOICES),
        }

You can see the updated class in this link.