Jarrod
Jarrod

Reputation: 1705

Sending POST data from inside a Django template 'for loop'

With this HTML:

...

    {% for thing in things %}
        <form method="post">
             {% csrf_token %}
             {{ thing.name }}
             {{ form.value }}
             <input type="submit" value="Submit" />
        </form>
    {% endfor %}
...

My website lists multiple 'things' from my database, so there can be many forms generated on the one page. How can I somehow determine in my views.py, which 'thing's' form is being submitted?

More elaboration:

Imagine you have a page of objects listed one after the other, and each object has a like button associated with it, that adds a like to the object it is next to. That's essentially what I'm trying to do here.

The problem is, I have a form that can process the like, but how do I take that like and add it to the object that it's displayed next to on the page? (by the aforementioned 'for loop')


I'm completely confused on how to go about this, am I looking at the problem the wrong way, or is there a standard idiom around this problem that I don't know about?

Thank you :)

Upvotes: 1

Views: 2812

Answers (2)

Daniel Hepper
Daniel Hepper

Reputation: 29977

The standard way to handle multiple forms of the same kind on one page with Django is to use Formsets.

It handles the annoying details like displaying errors on one form while preserving the input on others etc.

However, in your specific case that might be overkill. If you just want to create a like for an object, there isn't really any user input that needs to be validated, so you don't really need a form. Just perform a POST to a specified URL, maybe with Javascript. If the user messes with the URL, you display a 404.

Upvotes: 0

Ian Price
Ian Price

Reputation: 7616

The most common design pattern for model instance updates is to provide the primary key of an object in the url where you are submitting your post data.

# urls.py

from django.conf.urls import *
from library.views import UpdateThing

urlpatterns = patterns('',
    url('^update_thing/(?P<pk>[\w-]+)$', UpdateThing.as_view(), name='update_thing'),

# views.py

def my_view(request, pk=None):
    if pk:
        object = thing.objects.get(pk=pk)
    form = MyModelForm(data=request.POST or None, instance=object)

    if form.is_valid():
        ...

Now, let's specify (using Django's url template tag) that we want to submit post data for each object to the correct url.

{% for thing in things %}
    <form method="post" action="{% url 'update_thing' thing.pk %}">
         {% csrf_token %}
         {{ thing.name }}
         {{ form.value }}
         <input type="submit" value="Submit" />
    </form>
{% endfor %}

The url tag does a reverse lookup through your urls for the name kwarg supplied for a given url, and accepting positional arguments (such as, in this case, thing.pk) and, when needed, keyword arguments.

Upvotes: 1

Related Questions