The Django documenation seems to be very explicit that a POST must be redirected. I'm new to all of this, and when I deploy I'm not eager to be hacked. My question is: is the following view exploitable? I redirect when the post.cleaned_data is valid. Do I also need to redirect when it is not valid? Additionally, does a "recursive" view like this contain any security weaknesses?
def detail(request, blog_id):
b = get_object_or_404(Blog, pk=blog_id)
if request.method == 'POST':
form = CommentForm(request.POST)
if form.is_valid():
poster = form.cleaned_data['poster']
comment = form.cleaned_data['comment']
comment_date = timezone.now()
b.comment_set.create(poster=poster, comment_date=comment_date, comment=comment)
return HttpResponseRedirect(reverse('blog:detail', args=(b.id,)))
else:
return render(request, 'blog/detail.html', {
'blog': b,
'form': form,
})
form = CommentForm()
return render(request, 'blog/detail.html', {
'blog': b,
'form': form,
})
Additionally, for those with experience with testing, would you mind describing what steps I should take to fully test this view? I know how to test status codes. I have also tested the post method, and would like to know how to view the whole chain of redirects (e.g. The post gets called, and returns an HttpResponseRedirect but self.client.post stops there, and I want to continue through the next call where it recursively returns the get request at the end of the view. Thanks for your input in advance.
When the form is invalid, you need to render the view again, when you pass the same form object, it will display errors automatically, so no redirection in this case, this is how you make your view more clean:
def detail(request, blog_id):
b = get_object_or_404(Blog, pk=blog_id)
if request.method == 'POST':
form = CommentForm(request.POST)
if form.is_valid():
poster = form.cleaned_data['poster']
comment = form.cleaned_data['comment']
comment_date = timezone.now()
b.comment_set.create(poster=poster, comment_date=comment_date, comment=comment)
return HttpResponseRedirect(reverse('blog:detail', args=(b.id,)))
else:
form = CommentForm()
return render(request, 'blog/detail.html', {
'blog': b,
'form': form,
})
Regarding tests, to go through the redirect, you need to add follow
argument in the post method (it's set to False by default):
c.post('/login/', {'name': 'fred', 'passwd': 'secret'}, follow=True)