Barburka
Barburka

Reputation: 465

Django forms - set specific data to the form object before modelForm saving

I have two ModelForm objects in the same view - Person and Adress. After user has bounded , I'm saving Person object. After saving, I want to use that saved object to set the ForeignKey of AdressForm, validate that form, and save. How can I set this? I mean field in ModelForm()? I've searched everywhere, and ewerywhere is said I have to save(commit=False), but I can't save unvalidated form! When I valid(), there is blank ForeignKey field! Here's my code: (I try to avoid create method, rather save)

views.py

class KontrahentCreate(LoginRequiredMixin, generic.View):
    template = 'escrm/kontrahent_form.html'
    context = dict()
    message = "Utworzono pomyślnie nowego kontrahenta"

    def get(self, request):
        self.context['form_kontrahent'] = KontrahentForm(initial={'czy_aktywny': True})
        self.context['form_kontrahent'].fields['czy_aktywny'].widget = HiddenInput()
        self.context['form_adres'] = AdresKontrahentForm(initial={'czy_domyslny': True})
        self.context['form_adres'].fields['czy_domyslny'].widget = HiddenInput()
        self.context['title'] = 'Dodaj nowego kontrahenta'
        return render(request, self.template, self.context)

    def post(self, request):
        kontrahent_form = KontrahentForm(request.POST)
        adres_form = AdresKontrahentForm(request.POST)
        if kontrahent_form.is_valid():
            kontrahent = kontrahent_form.save()
        else:
            self.context['form_kontrahent'] = kontrahent_form
            return render(request, self.template, self.context)
        adres_form['kontrahent'].data = kontrahent.pk #AttributeError can't set attribute
        if adres_form.is_valid():
            adres_form.save()
        else:
            self.context['form_adres'] = adres_form
            return render(request, self.template, self.context)
        messages.success(self.request, self.message)
        return HttpResponseRedirect(reverse_lazy('escrm:kontarhent-detail', kwargs={'pk': kontrahent.pk}))

forms.py

class KontrahentForm(ModelForm):

    class Meta(ModelForm):
        model = Kontrahent
        fields = '__all__'


class AdresKontrahentForm(ModelForm):

    class Meta(ModelForm):
        model = AdresKontrahent
        fields = '__all__'
        widgets = {
            'kontrahent': forms.HiddenInput(),
        }

Upvotes: 0

Views: 405

Answers (2)

user2390182
user2390182

Reputation: 73450

You should exclude the kontrahent field from the adres form. Then the form will be valid without it! I added some other modifications (e.g. do not make your context a class variable). Also for the other fields that you provide initial values and hidden inputs for, consider excluding them from the form altogether. If you give them default values in the model, you can ignore them in the view, too:

class KontrahentForm(ModelForm):
    class Meta(ModelForm):
        model = Kontrahent
        exclude = ['czy_aktywny']  # consider default value on model!

class AdresKontrahentForm(ModelForm):
    class Meta(ModelForm):
        model = AdresKontrahent
        exclude = ['czy_domyslny', 'kontrahent']

# view
def get_form(self, formclass):
    if request.method == 'POST':
        return formclass(request.POST)
    return formclass()

def get_context(self, **kwargs):
    ctx = {}
    ctx['form_kontrahent'] = kwargs.get('kontrahent_form', self.get_form(KontrahentForm))
    ctx['form_adres'] = kwargs.get('adres_form', self.get_form(AdresKontrahentForm))
    ctx['title'] = 'Dodaj nowego kontrahenta' 
    return ctx

def get(self, request):
    return render(request, self.template, self.get_context())

def post(self, request):
    kontrahent_form = self.get_form(KontrahentForm)
    adres_form = self.get_form(AdresKontrahentForm)
    k_valid = kontrahent_form.is_valid()
    a_valid = adres_form.is_valid()
    if not (k_valid and a_valid):
        return render(
            request, self.template, 
            self.get_context(kontrahent_form=kontrahent_form, adres_form=adres_form))
    kontrahent = kontrahent_form.save(commit=False)
    kontrahent.czy_aktywny = True
    kontrahent.save()
    adres = adres_form.save(commit=False)
    adres.czy_domyslny = True
    adres.kontrahent = kontrahent
    adres.save()
    messages.success(self.request, self.message)
    return HttpResponseRedirect(reverse_lazy('escrm:kontarhent-detail', kwargs={'pk': kontrahent.pk}))

Upvotes: 1

Daniel Roseman
Daniel Roseman

Reputation: 599490

In all those places that said to use save(commit=False), they will also say that you should exclude the field from the form, rather than using fields = '__all__'. That way, the form won't be invalid.

Upvotes: 1

Related Questions