SilentDev
SilentDev

Reputation: 22767

Django / HTTP - Sending query string with a POST request - Is it not recommended?

This is my models.py:

class Blog(models.Model):
    user = models.ForeignKey(User)
    votes = models.IntegerField(default=0)

class BlogExtended(models.Model):
    blog = models.ForeignKey(Blog)
    usersVoted = models.ManyToManyField(User)

Basically, each blog has a user who created the blog. If users like someones blog, they can vote for it. Each time a blog gets a vote, the 'votes' counter goes up by one. In my template, I don't want the vote button to be a button which just says 'vote'. I want the vote button to be an image. Since once the user clicks the vote button, I am going to be altering the database (increasing the 'votes' field by one) I need to use a POST request. So this is what I initially had for my template (I initially used a GET request):

{% if Blogs %} <!-- Blogs is a list of blogs -->
     <ul class="blogs">
     {% for blog in Blogs %}
         <li>
             <a href="/vote/?id={{ blog.id }}" class="vote"><img src="images/voteButton.jpg" </a>

and this was my view which handles the /vote/ url:

def voteView(request):
     if request.GET.has_key('id'): #if it is a GET request which has the blogs id
         try:
             id = request.GET['id']
             blog = Blog.objects.get(id=id) #if the Blog is found
             blog.votes += 1 #make a change to the 'votes' field in the DB
             blog.blogextended_set.usersVoted.add(request.user) #make a change in the 'usersVoted' field in the DB
             blog.save()

but as you can see, I was using GET instead of POST. I realized I needed to use POST since I am altering the database, so this was my attempt at making it a POST request:

<form method="post" action="/vote/">{% csrf_token %}
    <button type="submit">
        <img src="images/voteButton.jpg" alt="vote" /> 
            <!-- I used button rather than input because with button, I was able to replace the button with an image.. I was unable to replace the button with an image -->
    </button>
</form>

This form sends basically no information to /vote/ (it only sends the current user object: request.user). I need to also send the ID of the blog. I was able to send the ID the intial way by adding a query string in the URL of the GET request. The only way I can think of to add the ID of the blog in my POST request is by adding a query string in the URL, so my form would action like this:

<form method="post" action="/vote/?id={{ blog.id }}">

I realized that sending a query string with a POST request is something I have never seen / done before. Is it okay if I send a query string with a POST request or is it not recommended? What problems could arise from sending a query string with a POST request?

Additional help: If it is not recommend, can anyone suggest another way of sending additional information along with the POST request?

Upvotes: 1

Views: 2135

Answers (2)

trinchet
trinchet

Reputation: 6933

You just need to add another field to your form:

<input type="hidden" name="blog_id" value="{{ blog.id }}" />

whole form:

<form method="post" action="/vote/">{% csrf_token %}
    <button type="submit">
        <img src="images/voteButton.jpg" alt="vote" /> 
    </button>
    <input type="hidden" name="blog_id" value="{{ blog.id }}" />
</form>

then, your view should look like:

def voteView(request):
     if request.POST.has_key('blog_id'): 
         try:
             id = request.POST['blog_id'] 
             ...

Upvotes: 2

xjtian
xjtian

Reputation: 1006

The better solution is the put the blog ID in a hidden field in your form, like so:

<form method="post" action="/vote/">
    {% csrf_token %}
    <input type="hidden" name="id" value="{{ blog.id }}">
    <button type="submit">
        <img src="images/voteButton.jpg" alt="vote" />
    </button>
</form>

In your view, you will be able to extract the ID of the blog post that was voted for using request.POST['id'].

Upvotes: 2

Related Questions