Why it can't pass a validation with the django form when set data after initializing

Question:

Why it can’t pass a validation when I set data like this (form.data=request.POST)

@login_required
def add_delivery_view(request):
    user = request.user
    delivery = (Delivery.objects.filter(user=user)  or [None])[0]
    form = AddDeliveryForm(instance=delivery)

    if request.method == 'POST':
        form.data = request.POST

        if form.is_valid():
            delivery = form.save(commit=False)
            delivery.user = request.user
            form.save()
            return redirect('/') 


    return render(request, 'order/add_delivery.html', {'form':form})

But when I set data like this, it works just fine

...

    if request.method == 'POST':
        form = AddDeliveryForm(data=request.POST, instance=delivery)

        if form.is_valid():
            delivery = form.save(commit=False)
...

I guess it something with initialization of form. Maybe I should add some method after form.data=request.POST

Question is: What is the difference underneath the hood?
Thanks in advance

Asked By: maisiq

||

Answers:

It sets extra fields, like .is_bound to True, which means that there is data (this can be through data=…, or files=…, or both). So it has some procedure that does not only set .data to the request.POST. While you could try to mimic this behavior, it is better to let the constructor do its work since certain forms might override the constructor, and in the future the behavior of Django’s Form might change as well.

It also looks quite ugly, constructing a form with data makes it clear the form will process the data. As for the .filter(…) part, this is equivalent to .first() [Django-doc], and it is better to let the form commit, since then it can save many-to-many fields as well, so:

@login_required
def add_delivery_view(request):
    delivery = Delivery.objects.filter(user=request.user).first()
    if request.method == 'POST':
        form = AddDeliveryForm(request.POST, request.FILES, instance=delivery)
        if form.is_valid():
            form.instance.user = request.user
            form
            return redirect('name-of-some-view')
    else:
        form = AddDeliveryForm(instance=delivery)
    return render(request, 'order/add_delivery.html', {'form': form})
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.