read which button in a loop was clicked.

Hello.
First I should preface this by saying I am completely new to Django, HTML and web development as a whole. so any explanation would be very appreciated.

I am trying to develop a site where there is a for loop going through multiple object, and object generates a button. How do I make Django know which object the buttons relate to. Specifically this happens in two instances. for example approval:

views.py:

 def userapproval(request):
     if request.method == "POST":
         form = Approval(request.POST)
         if form.is_valid():
             if form.decision == 'Approved':
                 form.related_id.change_status('Approved')
             #else:
                 # todo Email (message?) with the explanation for the denial
     return render(request=request, template_name='admin/user_approval.html',
                   context={"awaiting_approval": LabUser.objects.filter(approved=False),"form": Approval})

template:

 {% block content %}
 {% for applicant in awaiting_approval %}
     <p>Applicant name: {{applicant.username}}</p>
     <form method="POST">
         {% csrf_token %}
         {{form}}
         <button style="background-color:#CFCFCF; color:blue" class="btn btn-outline-info" type="submit">Submit</button>
     </form>
 <br>
 {% endfor %}
 {% endblock %}

here is the form:

class Approval(forms.Form):
    APPROVAL_CHOICES = [
        ('Approved', 'Approved'),
        ('Denied', 'Denied'),]
    decision = forms.CharField(label='Approval:', widget=forms.RadioSelect(choices=APPROVAL_CHOICES))
    reason = forms.CharField(max_length=100) # todo make mandatory if denied, disable otherwise
    related_id = None

How do I know which user from the users outputted in the for the admin approved? Another minor question while I am at it, how do I make the reason charfield only mandatory if denied and outright disable it if approved.

So, it’s been a while since I did proper HTML, but I believe if you give a name and value to the button elements in HTML, you’ll only get sent the one that the user clicked - then, you can look for them in request.POST and work out which one was pressed.

Update: I just read the code and it appears you’re asking about the radio buttons, not button buttons - my mistake. You’ll get that value from form.cleaned_data['decision'] (Django handles decoding what the user picked for you).

As for the charfield being mandatory only if denied - your best bet is to write a custom clean function for it on the form, something like this:

def clean_reason(self):
    if self.cleaned_data["decision"] == "Denied" and not self.cleaned_data["reason"]:
        raise forms.ValidationError("Reason must be provided when denying")
    return self.cleaned_data["reason"]

You can write those sorts of methods for any form field to do custom checks on them. Two things to look out for - they run in order (so this only works because you have the reason field after decision), and they need to return the new value of the field (so many times I have had fields end up with value None because I forgot to return the value)

I think I didnt explain myself properly. the page is for the admin to manually approve users. The admin should see:

Applicant A
[ ]Approve
[ ]Deny
Reason:
% Submit button%
Applicant B
[ ]Approve
[ ]Deny
Reason:
% Submit button%
Applicant C
[ ]Approve
[ ]Deny
Reason:
% Submit button%

Question is how do I know regarding which applicant the submit button was pressed.

and the radio button is just one of 3 cases where I have this problem. in the other two I use regular buttons. for example in user management I have

{% block content %}
 <table>
 <tr>
     <th>Username</th>
     <th>email</th>
     <th>Last login</th>
     <th>Joined</th>
     <th>Delete?</th>
     <th>Reset password</th>

 </tr>
 </table>
{% for user in users %}
<tr>
    <td>{{user.get_full_name()}}</td>
    <td>{{user.email}}</td>
    <td>{{.user.last_login}}</td>
    <td>{{user.date_joined}}</td>
    <form method="POST">
    {% csrf_token %}
    <td><input type="submit" name="DisableUser" value="Disable User" /></td>
    <td><input type="submit" name="ResetPassword" value="Reset Password" /></td>
    </form>
 </tr>
<br>
{% endfor %}
{% endblock %}

and just like that I have the same issue. Each users gets his own line, and each user has gets Disable/Reset button. how do I know from which line of buttons was pressed.

Ah, in that case I’d include a hidden form field called user_id with their ID in it. That way, you know which form was submitted.

How do I pass that user id? I assume I cant do it in the py files since the for loop is in the template. so where in

{% block content %}
{% for applicant in awaiting_approval %}
    <p>Applicant name: {{applicant.username}}</p>
    <form method="POST">
        {% csrf_token %}
        {{form}}
        <button style="background-color:#CFCFCF; color:blue" class="btn btn-outline-info" type="submit">Submit</button>
    </form>
<br>
{% endfor %}
{% endblock %}

can I pass a the applicant field to the form call?

You can just do it manually:

{% for applicant in awaiting_approval %}
<p>Applicant name: {{applicant.username}}</p>
<form method="POST">
    {% csrf_token %}
    {{form}}
    <input type="hidden" name="applicant_id" value="{{ applicant.id }}">
    <button style="background-color:#CFCFCF; color:blue" class="btn btn-outline-info" type="submit">Submit</button>
</form>
{% endfor %}
2 Likes

Can you explain what exactly is this form

See the docs on Working with Forms, particularly the section on Working with form templates.