3

views.py:

def index(request):
    return render_to_response('index.html', {})

def photos(request, artist):
    if not artist:
        return render_to_response('photos.html', {'error' : 'no artist supplied'})
    photos = get_photos_for_artist(artist)
    if not photos:
        logging.error('Issue while getting photos for artist')
        return render_to_response('photos.html', {'error': 'no matching artist found'})
    return render_to_response('photos.html', {'photos': photos})  

Index.html:

<html>
    <head>
        <title>find artist photos </title>
    </head>
    <body>
        {% block error %} {% endblock %}
        <form action="/photos" method="POST">
            {% csrf_token %}
            <label for="artist">Artist : </label>
            <input type="text" name="artist">
            <input type="submit" value="Search">
        </form>
        {% block content %}{% endblock %}
    </body>
</html>

photos.html:

{% extends 'index.html' %}
{% block error %}
    {% if error %}
        <p> {{ error}} </p>
    {% endif %}
{% endblock %}

{% block content %}
    {% if photos %}
        {% for photo in photos %}
            {{ photo }}
        {% endfor %}
    {% endif %}
{% endblock%}

url.py:

urlpatterns = patterns('',
    (r'', index),
    (r'^time/$', current_datetime),
    (r'^photos/(\w+)$', photos)
)

I even tried by adding {% csrf_token %}, but no luck

Thank you

UPDATE
I see these in the logs

UserWarning: A {% csrf_token %} was used in a template, but the context did not provide the value.  This is usually caused by not using RequestContext.
  warnings.warn("A {% csrf_token %} was used in a template, but the context did not provide the value.  This is usually caused by not using RequestContext.")  

This came after adding context_instance=RequestContext(request) **to render_to_response()**

daydreamer
  • 87,243
  • 191
  • 450
  • 722

7 Answers7

9

add context_instance=RequestContext(request) to every view that you will use a form inside it:

return render_to_response('index.html', {}, context_instance=RequestContext(request) )


return render_to_response('photos.html', {'photos': photos}, context_instance=RequestContext(request) )
karthikr
  • 97,368
  • 26
  • 197
  • 188
Kambiz
  • 1,217
  • 9
  • 8
  • 5
    ...or if you use Django 1.3, you can use a shorter version of this: `render(request, 'index.html', {})` https://docs.djangoproject.com/en/1.3/topics/http/shortcuts/#render – Lepi Dec 07 '11 at 04:40
5

Supposing you are using a fairly recent version of Django (1.3/1.4/dev) you should follow these steps :

  • In settings.py, Add the middleware django.middleware.csrf.CsrfViewMiddleware to the MIDDLEWARE_CLASSES list.
  • In your template, use the {% crsf_token %} in the form.
  • In your view, ensure that the django.core.context_processors.csrf context processor is used either by :
    • use RequestContext from django.template
    • directly import the csrf processor from from django.core.context_processors

Examples

from django.template import RequestContext
from django.shortcuts import render_to_response

def my_view(request):
    return render_to_response('my_template.html', {}, context_instance=RequestContext(request))

or

from django.core.context_processors import csrf
from django.shortcuts import render_to_response

def my_view(request):
    c = {csrf(request)}
    return render_to_response('my_template.html', c)

References

(exhaustive post for posterity and future viewers)

sberder
  • 4,505
  • 2
  • 26
  • 15
3

A number of things to troubleshoot here:

  • Please load your "index" page in a web browser, do "View Source", and check if the {% csrf_token %} is being expanded. It should be replaced with an <input> tag. If that's not happening, then you have problems with your index page. If it is being replaced correctly, then you have problems with your photos page.

  • The POST URL in index.html doesn't match any of the patterns in urls.py. Your urls.py seems to expect the search term to be part of the URL, but it's not - you're sending it as a HTTP POST parameter. You need to access it via request.POST.

user9876
  • 10,954
  • 6
  • 44
  • 66
  • Good points. It is usually better to do searches with a GET instead of a POST method as they can then be bookmarked. So I would suggest changing the template, over changing the view. One or the other does need to be changed. – mtnpaul Dec 08 '11 at 03:36
  • Actually , this is the Ultimate solution! I ran across a lot of articles mentioning this problem, but only this one point out the truth. Please render the index page with Requestcontext as well. – spikeyang Feb 21 '14 at 11:22
2

Check in the settings, if you have this middleware:

'django.middleware.csrf.CsrfViewMiddleware'

https://docs.djangoproject.com/en/dev/ref/contrib/csrf/

Tadeck
  • 132,510
  • 28
  • 152
  • 198
Goin
  • 3,856
  • 26
  • 44
1

You may need to explicitly pass in a RequestContext instance when you use render_to_response in order to get the CSRF values for that template tag.

http://lincolnloop.com/blog/2008/may/10/getting-requestcontext-your-templates/

kungphu
  • 4,592
  • 3
  • 28
  • 37
0

Try using the @csrf_protect decorator:

from django.views.decorators.csrf import csrf_protect
from django.shortcuts import render_to_response

@csrf_protect
def photos(request,artist):
    if not artist:
        return render_to_response('photos.html', {'error' : 'no artist supplied'})
    photos = get_photos_for_artist(artist)
    if not photos:
        logging.error('Issue while getting photos for artist')
        return render_to_response('photos.html', {'error': 'no matching artist found'})
    return render_to_response('photos.html', {'photos': photos})  
andersem
  • 724
  • 1
  • 8
  • 19
  • Tried that, but it in that case doesn't seem to be calling photos function, logs say [06/Dec/2011 18:08:05] "GET / HTTP/1.1" 200 403 [06/Dec/2011 18:08:08] "POST /photos HTTP/1.1" 200 403 – daydreamer Dec 07 '11 at 00:11
  • I guess you've seen this: "By default, a '403 Forbidden' response is sent to the user if an incoming request fails the checks performed by CsrfViewMiddleware. This should usually only be seen when there is a genuine Cross Site Request Forgery, or when, due to a programming error, the CSRF token has not been included with a POST form." from https://docs.djangoproject.com/en/dev/ref/contrib/csrf/. It seems the CSRF-token is not properly transmitted somehow. – andersem Dec 07 '11 at 00:13
  • If you add csrf_protect to the index view? – andersem Dec 07 '11 at 00:16
  • I added @csrf_protect in both index and photos, but no luck! I am sure its programming error, but not sure where – daydreamer Dec 07 '11 at 00:19
-1

This worked for me:

{% csrf_token %} In the template, there is a {% csrf_token %} template tag inside each POST form that targets an internal URL.

In views.py:

from django.template import RequestContext

...

...

...

return render_to_response("home.html", {}, context_instance=RequestContext(request))