2

I have this view which adds replies to a topic:

@login_required
def post_reply(request, topic_id):
    tform = PostForm()
    topic = Topic.objects.get(pk=topic_id)
    args = {}
    if request.method == 'POST':
        post = PostForm(request.POST)

        if post.is_valid():

            p = post.save(commit = False)
            p.topic = topic
            p.title = post.cleaned_data['title']
            p.body = post.cleaned_data['body']
            p.creator = request.user
            p.user_ip = request.META['REMOTE_ADDR']

            p.save()

            tid = int(topic_id)


        args['topic_id'] = tid
        args['topic'] = topic
        args['posts'] = Post.objects.filter(topic_id= topic_id).order_by('created')
        return render_to_response("myforum/topic.html",args)            

    else:
        args.update(csrf(request))
        args['form'] = tform
        args['topic'] = topic
        return render_to_response('myforum/reply.html', args, 
                                  context_instance=RequestContext(request))

The problem is that when user refershes the page after posting a reply her reply is being duplicated. How to avoid this?

UPDATE:Here is the related template:

{% extends "base.html"%}
{% load static %}


{% block content%}

<div class="panel">
    <div class="container">
<!-- Posts  -->
<div class="col-md-12">
    <h3>{{ topic.title }}</h3>
<table class="table table-striped">

    <tr class="col-md-9"><td>{{ topic.description }}</td></tr>
    <tr class="col-md-3"><div class="userpanel"><td>{{ topic.created }}</td></div></tr>

    {% for post in posts %}
         <tr class="col-md-12 userpanel"><td>{{ post.title }}</td></tr>


        <tr class="">
            <td>
               <div class="col-md-9 userpanel">{{ post.body }} <br> {{ post.created }} </div> 
            </td>
            <td>
                <div class="col-md-3 userpanel">{{ post.creator }} <br> {{ post.created }} </div>
            </td>
        </tr>

    {% endfor %}
</table>

<hr />
<!-- Next/Prev page links  -->
{% if posts.object_list and posts.paginator.num_pages > 1 %}
<div class="pagination">
    <span class="step-links">
        {% if posts.has_previous %}
            <a href= "?page={{ posts.previous_page_number }}">previous &lt;&lt; </a>
        {% endif %}

        <span class="current">
            &nbsp;Page {{ posts.number }} of {{ topics.paginator.num_pages }}
        </span>

        {% if posts.has_next %}
            <a href="?page={{ posts.next_page_number }}"> &gt;&gt; next</a>
        {% endif %}
    </span>
</div>
{% endif %}
<a class="button" href="/forum/reply/{{topic.id}}"> Reply </a>

</div> <!-- End col-md-12  -->

</div> <!-- End container  -->
</div>

{% endblock %}
supermario
  • 2,625
  • 4
  • 38
  • 58

1 Answers1

6

Always - I repeat, always, redirect after a POST.

So instead of doing a return render_to_response("myforum/topic.html",args) when your form is valid, do a return HttpResponseRedirect(url_of_your_view) (https://docs.djangoproject.com/en/1.7/ref/request-response/#django.http.HttpResponseRedirect)

Update after OP's comments:

You should use reverse (https://docs.djangoproject.com/en/1.7/ref/urlresolvers/#reverse) to create the url to redirect to:

return HttpResponseRedirect(reverse('myforum.views.topic', args=[topic_id]))

Also, I recommend to name your views (and drop strings for defining them since they are deprecated), so change your urls.py line like this: from myforum.views import topic ... url(r'^topic/(\d+)/$', topic, name='view_topic'), ...

And then just do a reverse('view_topic', args=[topic_id]) to get the url of your view.

Serafeim
  • 14,962
  • 14
  • 91
  • 133
  • Yes, always. This is definitely not restricted to Django, you should do this in any web framework. – knbk Feb 17 '15 at 16:05
  • Alright. Would you please elaborate how to append the page to url_of_my_view in HttpResponseRedirect ? – supermario Feb 17 '15 at 16:06
  • What is your urls.py entry for rendering that view? – Serafeim Feb 17 '15 at 16:07
  • Strangely I get this error now: `Reverse for 'myforum.views.topic' with arguments '(u'2',)' and keyword arguments '{}' not found. 0 pattern(s) tried: []` (where `2` is topic_id) – supermario Feb 17 '15 at 16:21
  • Ok, I managed it using good ol' fashion way: `return HttpResponseRedirect('/forum/topic/%s' % topic_id)` . Please add this and I'll accept the answer. – supermario Feb 17 '15 at 16:40
  • 1
    @supermario hard-coding urls is *not* DRY! Could you try my recommendation with adding a ``name='view_topic'`` kwarg to url and then using ``reverse('view_topic', args=[topic_id])`` ? – Serafeim Feb 17 '15 at 19:02