user14887093
user14887093

Reputation:

Django how to solve saving empty form problem?

I am trying take 2 different forms in one page in my Django project.

They have different form models but they are in the same page and use the same view function.

When I try them both of them works, but when I post one of them, the other one is also saving as a empty form. But I do not want this.

Why this is happening?

views.py

def ocr(request, id):
    ...
    pdf = get_object_or_404(Pdf, id=id)
    approval = ApprovalProcess(user_id=request.user, highest_rank=1)

    #FORM 1
    if request.method == 'POST':
        form = PdfRiskForm(request.POST, request.FILES, instance=pdf)

        if form.is_valid():
            form.save()

            if pdf.risk_rating == "Low Risk":
                n = len([x for x in doa_low_list if x < pdf.credit_limit])
                approval.highest_rank = n
            elif pdf.risk_rating == "Medium Risk":
                n = len([x for x in doa_medium_list if x < pdf.credit_limit])
            ....
            approval.save()

    else:
        form = PdfRiskForm()

    #FORM 2 
    if request.method == 'POST':
        form_2 = CommentForm(request.POST or None)

        if form_2.is_valid():
            form_2.instance.comment_other = form.cleaned_data.get("comment_other")
            form_2.instance.username = request.user
            form_2.instance.comp_name = userP[0].company
            form_2.instance.doc_id = pdf

            if form_2.comment_others is not None:
                form_2.save()

    else:
        form_2 = CommentForm()

models.py

class PdfRiskForm(forms.ModelForm):
    risk_rating = forms.ChoiceField(label='Risk Rating', choices=Pdf.RISK_RATING)
    credit_limit = forms.IntegerField()
    comments = RichTextField
    letter_portion = forms.IntegerField(min_value=0, max_value=100, required=False, label="Guarantee Portion (%)")

    class Meta:
        model = Pdf
        fields = ['risk_rating', 'credit_limit', 'letter_portion', 'comments']

class CommentFromOthers(models.Model):
    comp_name = models.ForeignKey(CompanyProfile, on_delete=models.CASCADE, null=True)
    doc_id = models.ForeignKey(Pdf, on_delete=models.DO_NOTHING, null=True)
    comment_others = RichTextField(blank=True)
    created_date = models.DateTimeField(default=datetime.now())
    username = models.ForeignKey(UserProfile, on_delete=models.CASCADE)

template.html

    <div class="card-body">
        <form method="POST" enctype="multipart/form-data">
            <!-- Very Important csrf Token -->
            {% csrf_token %}
            {{ form.media }}
            {{ form|crispy }}
            <input type="submit" class="btn btn-primary btn-lg" value="Approve">
        </form>
    </div>

    ...

    <div id="demo" class="collapse">
        <form method="POST" enctype="multipart/form-data">
           <!-- Very Important csrf Token -->
           {% csrf_token %}
           {{ form_2.media }}
           {{ form_2|crispy }}
           <input type="submit" class="btn btn-primary btn-lg" value="Send">
        </form>
     </div>

Upvotes: 0

Views: 1071

Answers (2)

AKX
AKX

Reputation: 169416

It'd be better to handle the forms in different view functions.

If you're bent on handling both forms in the same function, you will need to add a "marker" field that you check before you attempt to validate the form.

if request.method == 'POST' and request.POST.get('form') == 'risk': 
    form = PdfRiskForm(...)
elif request.method == 'POST' and request.POST.get('form') == 'comment': 
    form = ...

and then submit the form field along with the form you're submitting:

<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
<input type="hidden" name="form" value="risk" /> <!-- or comment -->

Upvotes: 1

Ralf
Ralf

Reputation: 16515

Another approach could be to send each form to a different URL (each with its own view).

The 2 forms can still be in the same HTML page (same template), but you specify a different action attribute for each.

        <form method="POST" enctype="multipart/form-data"
              action="/my-url-1/">
            ...
        </form>

        ...

        <form method="POST" enctype="multipart/form-data"
              action="/my-url-2/">
            ...
        </form>

This way you can simplify each view and no unnecessary data (meaning: the other forms data) gets POSTed to the views.

Upvotes: 0

Related Questions