Manage multiple languages ​​with django-hvad in one formset

I am using django-hvad to edit objects in different languages. I got a form (for an object) and a set of forms (for object attributes in different languages) as described in the documentation . The set of shapes is shown in a tab on the language that is created using django-crunchy shapes.

Everything works fine as long as I don't use initials. My goal is to preselect the language and hide the language_code field so you can enter multiple languages, but you don't need to:

forms.py:

languages = [x[0] for x in settings.LANGUAGES]


class MyTitleTranslationForm(forms.ModelForm):
    # language_code = forms.CharField()

    class Meta:
        fields = ['title']  # , 'language_code'

    def __init__(self, *args, **kwargs):
        super(MyTitleTranslationForm, self).__init__(*args, **kwargs)
        # self.fields['language_code'].widget = forms.HiddenInput()

        # Crispy
        self.helper = FormHelper()
        self.helper.form_tag = False
        self.helper.label_class = 'col-md-3'
        self.helper.field_class = 'col-md-9'

        self.helper.layout = Layout(
            Div('id', 'title', 'language_code', 'DELETE',
                role="tabpanel", css_class="tab-pane", css_id=self.initial.get('language_code'))
        )


class MyBaseTranslationFormSet(BaseTranslationFormSet):
    def __init__(self, *args, **kwargs):
        super(MyBaseTranslationFormSet, self).__init__(*args, **kwargs)

        self.used_language_codes = []
        self.languages = []

        actual_language = False

        counter = 0
        for form in self.forms:
            if form.instance.id:
                actual_language = form.initial.get('language_code', 'de')
            else:
                for language in languages:
                    if language not in self.used_language_codes:
                        actual_language = language
                        break

            self.used_language_codes.append(actual_language)
            self.languages.append({
                'language': actual_language,
                'error': bool(form.errors)
            })

            # DANGEROUS LINE
            form.fields['language_code'].initial = actual_language

            form.helper.layout.fields[0].css_id = actual_language
            if counter == 0:
                form.helper.layout.fields[0].css_class += " active"
            counter += 1

      

Somewhere in django-hvad the initials are set or overridden again, so the form is anchored. This results in invalid data because the content field for each language is blank. It works as long as I set the initials in the same order as in the settings. LANGUAGES, but this can lead to duplicate languages ​​if you only fill in the second tab / language: If you reload the view, both first tabs are filled with the second language. The first is because of the pre-filled form in the formset, and the second is because of the initial one.

views.py:

class CategoryEditView(TranslatableUpdateViewMixin, UpdateView):
    model = Category
    success_url = reverse_lazy('category:list-view')
    form_class = modelform_factory(Category, form=CategoryForm)
    translationformset_class = translationformset_factory(Category, form=MyTitleTranslationForm,
                                                          formset=MyBaseTranslationFormSet,
                                                          extra=len(settings.LANGUAGES),
                                                          max_num=len(settings.LANGUAGES))

    def get_context_data(self, **kwargs):
        context = super(_TranslatableViewMixin, self).get_context_data(**kwargs)
        context['translationformset'] = self.translationformset_class(instance=self.object)
        return context

    def post(self, request, *args, **kwargs):
        form = self.form_class(request.POST, request.FILES, instance=self.object)
        translationformset = self.translationformset_class(request.POST, request.FILES, instance=self.object)

        if form.is_valid() and translationformset.is_valid():
            self.object = form.save(commit=False)
            translationformset.instance = self.object
            translationformset.save()
            self.object.save()
            form.save_m2m()

            return redirect(self.get_success_url())
        else:
            return render(request, self.get_template_names(), {
                'form': form,
                'translationformset': translationformset
            })

      

The category form and form category are pretty standard, so I am not attaching them. I'm really wondering if anyone has encountered a similar problem, or even might suggest a solution for one key question: How can I dynamically set initials in a formset?

Cheers, Marius

+3


source to share





All Articles