Making a django html template request with multiple key values - javascript

I'm new to using Django or even creating a website, so please bear with me if I have provided too little/much detail about the issue I'm facing. Also, I've spent the better part of the last week trolling SO pages, blogs, Django tutorials, Django documentation, etc. trying to solve the issue myself. Maybe I've overlooked something or I'm just unlucky, but nothing I've found addresses my particular situation in its entirety. Most examples seem to focus on handling requests in views.py and not on how the original request is made in the Django template.
I have a Django template, view_table.html, that displays a Bootstrap DataTable table object to a user. The second column of this table is a BigIntegerField called MyRow_ID. I currently have code in MyCode.js that allows the user to highlight multiple rows, and when button modify_button is clicked, the MyRow_ID values for the selected rows (e.g. [2, 13, 14]) are captured into a JS dict called sent_data. After these values have been captured, I'd like for modify_button to create a GET request that sends sent_data along with it. After matching in urls.py and calling the modify_data function in views.py, modify_data should render a new page modify_table.html while passing back the model instances matching MyRow_ID in order to display only the selected rows' data. I think I'm really close, and perhaps only a tweak to the regex expression is what I need, but here are my questions:
How do I create a GET request in the Django template view_table.html that passes sent_data along to Django? Currently I'm using a form with the method and action attributes set to "GET" and "{% url 'modify_data' sent_data=sent_data %}" respectively. I'm assuming GET and not POST should be used because the request isn't modifying the backend, it's more of a "filter the view" type of request. Is this a correct assumption? What would the requested url look like? Say MyRow_ID values are [2,13,14]. Would the get request look something like /modify_data/matched_row_1=2&matched_row_2=13&matched_row_3=14? Do I have to create this url string myself in the template by iterating over sent_data and attaching a "matched_row_n=" string, or is there a simpler way for the template to create this automatically in the request?
What's the correct regex pattern that should be used in myapp/urls.py, given sent_data could have anywhere from 1 to n unique MyRow_ID values, assuming 1 to n rows are selected respectively? (Obviously robust code would include handling where 0 rows are selected and modify_button is clicked, but let's set that aside for now.) Currently I'm getting a NoReverseMatch Error at /myapp/view_data/: Reverse for 'modify_data' with arguments '()' and keyword arguments '{u'sent_data': ''}' not found. I'm new to using regex, and I know what I have in myapp/urls.py is wrong.
Is the code in myapp/views.py correct to filter the matching model instances and render modify_table.html with the selected rows?
view_table.html:
<!DOCTYPE html>
<html>
<head>
## Bunch of code… ##
</head>
<body>
<div class="col col-xs-12 text-right">
<form style="display" method="get" action="{% url 'modify_data' sent_data=sent_data %}">
<button id="modify_button" type="button" class="btn btn-primary btn-create">Modify Data</button>
</form>
</div>
<br><br><br>
<table id="my_table">
## Code that displays my_table ##
</table>
<!-- Execute JS scripts -->
<script type="text/javascript" src="{% static "myapp/js/jquery-1.12.0.min.js" %}"></script>
<script type="text/javascript" src="{% static "myapp/js/jquery.dataTables.min.js" %}"></script>
<script type="text/javascript" src="{% static "myapp/js/bootstrap.min.js" %}"></script>
<script type="text/javascript" src="{% static "myapp/js/dataTables.bootstrap.min.js" %}"></script>
<script type="text/javascript">
var sent_data = [];
</script>
<script type="text/javascript" src="{% static "myapp/js/MyCode.js" %}"></script>
</body>
</html>
MyCode.js:
$(document).ready(function(){
var oTable = $('#my_table').DataTable();
var selected_data = [];
$('#my_table tbody').on('click','tr',function(){
$(this).toggleClass('active');
});
$('#modify_button').click(function(event){
selected_data = $.map(oTable.rows('.active').data(), function (item) {
return item[1]
});
sent_data = { 'modify_rows': selected_data };
});
});
I should note that I'm using MyRow_ID and not the native DataTable attribute rowID because I'm assuming DataTable's automatically-created rowID do not match the automatically-created primary keys (pk) that Django is using. Is this a correct assumption?
myapp/urls.py:
from django.conf.urls import url
from . import views
from .models import MyDataModel
urlpatterns = [
url(r'^view_data/$', views.view_data, name='view_data'),
url(r'^modify_data/(?P<sent_data>\d+)/$', views.modify_data, name='modify_data'),
]
myapp/views.py:
from django.forms import modelformset_factory
from django.shortcuts import render
from django.http import HttpResponse
from .models import MyDataModel
def view_data(request):
myData = MyDataModel.objects.all()
return render(request, 'myapp/view_table.html', {'myData': myData})
def modify_data(request, sent_data):
MyDataFormSet = modelformset_factory(MyDataModel, fields=('MyRow_ID','MyRow_Text'))
if request.method == 'GET':
selected_rows = sent_data['modify_rows']
## selected_rows = request.GET['modify_rows']
formset = MyDataFormSet(queryset=MyDataModel.objects.filter(MyRow_ID__in=selected_rows))
selected_data = MyDataModel.objects.filter(MyRow_ID__in=selected_rows)
return render(request, 'myapp/modify_data.html', {'formset': formset, 'selected_data': selected_data})
else:
return HttpResponse('A GET request was not received.')
Finally, modify_data.html:
<!DOCTYPE html>
<html>
<head>
## Bunch of code… ##
</head>
<body>
<div class="col col-xs-12 text-right">
<form method="post" action="">
{% csrf_token %}
{{ formset }}
<button id="submit_changes" type="button" class="btn btn-primary btn-create">Submit Changes</button>
</form>
</div>
<br><br><br>
<table id="selected_rows_table">
## Code that displays selected rows passed as selected_data ##
</table>
</body>
</html>
Any help is much appreciated, thank you in advance!

Through much trial and error and good old-fashioned googling I was able to work out the above issues and gain a better understanding of query strings, regex patterns and even how to use an AJAX request to accomplish my original goal.
My original goal had been to allow the user to select multiple rows of data, click a button, and then edit them simultaneously in a form, said form either being rendered on a new page or in a modal. The following posts/blogs were very helpful for each piece of the puzzle:
Django documentation on urls, request/responses and model formsets:
https://docs.djangoproject.com/en/1.10/topics/http/urls/
https://docs.djangoproject.com/en/1.10/ref/request-response/
https://docs.djangoproject.com/en/1.10/topics/forms/modelforms/#model-formsets
Guide to creating Bootstrap modals:
https://coolestguidesontheplanet.com/bootstrap/modal.php
Understanding of how urls and query strings work with multiple values for a single key:
http://meyerweb.com/eric/tools/dencoder/ (for testing)
How to pass multiple values for a single URL parameter?
Capturing url parameters in request.GET
Example of using Django AJAX Form:
http://schinckel.net/2013/06/13/django-ajax-forms/
Code for handling response from server of an AJAX request, and refreshing the page:
Update div with jQuery ajax response html
One important thing to note about using a query string with multiple values for a single key, e.g. say the url of my GET request is something like www.myurl.com/?page=1&page=2&page=3; when using an AJAX GET request, it will create a query string for this url with www.myurl.com/?page[]=1&page[]=2&page[]=3, i.e. it adds the "[]" brackets for any key with multiple values. The usual answers (as documented by Django and others) to retrieve all values of the "page" key in views.py when processing the request is to use request.GET.getlist('page'). THIS WILL NOT WORK. You need to use request.GET.getlist('page[]'). Add the brackets in request.method.getlist() or remove them from the original query string in the url requested.
Finally, here are some snippets of modified code that addressed my original questions:
In view_data.html, updated form:
<form id="modify_form" method="post" action="{% url 'modify_data' %}">
{% csrf_token %}
{{ formset }}
</form>
In myapp/urls.py, fixed url finder to handle any query string passed:
url(r'^modify_data/$', views.modify_data, name='modify_data'),
In myapp/views.py, change modify_data code:
def modify_data(request):
MyDataFormSet = modelformset_factory(MyDataModel, fields=('MyRow_ID','MyRow_Text'))
if request.is_ajax():
template = 'myapp/view_data.html'
else:
template = 'myapp/modify_data.html'
if request.method == 'GET':
selected_rows = request.GET.getlist['modify_rows[]']
formset = MyDataFormSet(queryset=MyDataModel.objects.filter(MyRow_ID__in=selected_rows))
selected_data = MyDataModel.objects.filter(MyRow_ID__in=selected_rows)
return render(request, template, {'formset': formset, 'selected_data': selected_data})
else:
return HttpResponse('A GET request was not received.')
In MyCode.js, code has been updated to reflect using modal form, AJAX GET request and refreshing the DOM with Django view.py's response:
$("#modify_button").click(function(){
selected_data = $.map(oTable.rows('.active').data(), function (item) {
return item[1]
});
$.ajax({
// The URL for the request
url: URL,
// The data to send (will be converted to a query string)
data: {
modify_rows: selected_data,
},
// Whether this is a POST or GET request
type: "GET",
})
// Code to run if the request succeeds (is done);
// The response is passed to the function
.done(function( json ) {
var forms_result = $('<div />').append(json).find('#modify_form').html();
$('#modify_form').html(forms_result);
var table_result = $('<div />').append(json).find('#my_table').html();
$('#my_table').html(table_result);
})
// Code to run if the request fails; the raw request
// and status codes are passed to the function
.fail(function( xhr, status, errorThrown ) {
alert( "Sorry, there was a problem!" );
console.log( "Error: " + errorThrown );
console.log( "Status: " + status );
console.dir( xhr );
})
});
Hope all of this is somewhat helpful to someone else, if not, this whole process has been a great learning experience for me!

Related

Why does my http response keep showing like an html page?

Here's the thing: I thought I could receive an HTTP response and manage it with javascript ajax and do whatever I wanted with that response without the user even noticing. For example using console.log(response).
But it's not working and the response is showing in text form like an html.
I'll explain what I'm doing and my problem:
I'm making a comment section for a django app. My comment system was working fine. The user could post comments and see other peoples comments.
The thing is that I had to refresh the page every time to load the recently published comments.
That's not very cool, I want to be able to post a comment and see it immediately without reloading the page.
I did my research and found this comment on quora
You use AJAX and a Django backend view.
Something (a user leaving a new comment, a timer etc.) will trigger a
JavaScript AJAX call to a Django view requesting comments for the
page. That Django view will return the result to the JavaScript AJAX
call. It can be done in two ways:
it can just return the data, typically in JSON and then JavaScript
worries about rendering that data on the page
or, the view can run the
data through a Django template and return the partial HTML and then
the JavaScript just needs to swap out the HTML response chunk in the
content area for the comments (typically identified by a HTML ID,
where you replace the HTML content of the div with a certain ID with
the HTML you received from the view both approaches have pros and cons
and which is better depends on many factors
I am trying to follow the second way.
My problem is that the HttpResponse changes my entire page and displays what's in the response as html text!
Here's my views.py. This is the view that renders the page where the comment section is at
(I'm not sending the rendered html yet because I'm having problems with HTTP response)
def make_bid(request, pk):
listing = Listing.objects.get(id = pk)
comments = listing.comments.all()
if request.method == "POST":
if request.user.is_authenticated:
comment = Comment(
user = request.user,
comment= request.POST['comment'],
date = datetime.datetime.now().date(),
listing = listing)
comment.save()
context = {'comments': listing.comments.all()}
rendered = render_to_string("auctions/comments.html", context)
return HttpResponse("this a http response")
else:
return HttpResponse("user is not even authenticated")
else:
return render(request, "auctions/make-bid.html", {
'article' : listing,
'comments': comments
})
The html for the comment section
<aside class="comment__section">
<h3>Comments</h3>
<form action="{% url 'make-bid' article.id %}" method="post" id="form-comment">
{% csrf_token%}
<textarea id="textbox" class="field form__field--block" value="" name="comment" placeholder="What do you think about this listing?"></textarea>
<input class="button button__primary" type="submit" value="Publish">
</form>
<section class="comment__container">
<!-- comments from the http response should be inserted here with javascript-->
</section>
</aside>
The javascript. I copied this from another stackoverflow question. I was doing it myself with plain javascript and thought that might be the problem. It's not. It still doesn't give me the result I want
<script>
aside = document.querySelector(".comment__section")
// this is the id of the form
$("#from-comment").submit(function(e) {
e.preventDefault(); // avoid to execute the actual submit of the form.
var form = $(this);
var url = form.attr('action');
$.ajax({
type: "POST",
url: url,
data: form.serialize(), // serializes the form's elements.
success: function(data)
{
alert(data); // show response from the php script.
console.log('Submission was successful.');
console.log(data);
},
error: function(data){
console.log("no response")
}
});
});
</script>
I already tried using return JsonResponse. And still the same result :(
I am really lost here. I'm very new to Django and server-side stuff. And I have no idea why is the response showing like a whole page?
What am i missing?
Do http responses actually work differently as I think they do?
I would really appreciate any help. Thank you!!!
You have to serialize the data. Means, to convert django queryset into json format to send it to ajax.
from django.core import serializers
def make_bid(request, pk):
listing = Listing.objects.get(id = pk)
comments = listing.comments.all()
if request.method == "POST":
if request.user.is_authenticated:
comment = Comment(
user = request.user,
comment= request.POST['comment'],
date = datetime.datetime.now().date(),
listing = listing)
comment.save()
comments = listing.comments.all()
serialized_qs = serializers.serialize('json', list(comments))
data = {"queryset" : serialized_qs}
return JsonResponse(data)
else:
return HttpResponse("user is not even authenticated")
else:
return render(request, "auctions/make-bid.html", {
'article' : listing,
'comments': comments
})
I fixed it! My main problem was me. I made a few stupid mistakes. I had a typo and jquery wasn't loading. Here's how the script looks now:
<script src="{%static 'auctions/scripts/jquery-3.6.0.js' %}"></script>
<script>
$(document).ready(function(){
$("#form-comment").submit(function(e) {
e.preventDefault(); // avoid to execute the actual submit of the form.
var form = $(this);
var url = form.attr('action');
$.ajax({
type: "POST",
url: url,
data: form.serialize(), // serializes the form's elements.
success: function(data)
{
$("#comments").html(data);
$("#textbox").val('')
},
error: function(data){
console.log("no response")
}
});
});
})
</script>
And views.py. Now I'm sending the rendered comment section with an HttpResponse
def make_bid(request, pk):
listing = Listing.objects.get(id = pk)
context = {'comments': listing.comments.all()}
rendered = render_to_string("auctions/comments.html", context)
if request.method == "POST":
if request.user.is_authenticated:
comment = Comment(
user = request.user,
comment= request.POST['comment'],
date = datetime.datetime.now().date(),
listing = listing)
comment.save()
context = {'comments': listing.comments.all()}
rendered = render_to_string("auctions/comments.html", context)
return HttpResponse(rendered)
else:
return HttpResponse("user is not even authenticated")
else:
return render(request, "auctions/make-bid.html", {
'article' : listing,
'comments': rendered
})
And html looks like this
<aside class="comment__section" >
<h3>Comments</h3>
<form method="post" id="form-comment">
{% csrf_token%}
<textarea id="textbox" class="field form__field--block" value="" name="comment" placeholder="What do you think about this listing?"></textarea>
<input class="button button__primary" type="submit" value="Publish">
</form>
<section class="comment__container" id="comments">
{{comments}}
</section>
</aside>
I would still love to see a way to make the ajax call and handle the response with javascript. But I'm done with this comments section for now!
Thanks to everybody who answered this question!

How to refresh part of a Django page with AJAX?

I am deploying a website using Django. There is an application called 'forum', supporting a discussion forum on my website.
The url of the discussion forum is 'XXX.com/forum/roomY'. I want to refresh a div id = ''chat'', which includes a message list, on this page when users click a refresh button. I want to use AJAX to do that.
But I find that I could not call the function updatestatementlist(request) to retrieve the updated message list so it can be passed to the on this page.
/forum/views.py def updatestatementlist(request):
log.debug("call statementlist function")
statements = Statement.objects.filter(discussion=discussion)
return render(request, 'forum/statementlist.html', {
'statements': statements
})
I cannot see the log info so I think by clicking the button I fail to call this function.
The main html page of the discussion forum is /forum/discussion.html, which is under the template folder. I extract the html code within the div id = "chat" to a separate html /forum/statementlist.html as suggested here and several other SO posts.
/forum/discussion.html
<button id = "Refresh"> Refresh </button>
<div id="chat">
{% include 'forum/statementlist.html' %}
</div>
/forum/statementlist.html
{% load mptt_tags %}
{% recursetree statements %}
// display each statement
{% endrecursetree %}
forum.js
//When users click the refresh button
$("#Refresh").on("click", function(event){
alert("Refresh clicked")
$.ajax({
url: '',
type: "GET",
success: function(data) {
alert("success")
var html = $(data).filter('#chat').html();
$('#chat').html(html);
}
});
});
I also tried a few other url in this AJAX request: {% url updatestatementlist %}, {% url 'updatestatementlist' %}. But then I think it should be set to empty because I don't want to be redirected to another url. The discussion forum has a url of 'XXX.com/forum/roomY', by clicking the refresh button on this page I only want to refresh the div and fetch an updated statement list from the server.
BTW, I can see the two alerts after I click the button.
/forum/urls.py
urlpatterns = [
...
url(r'^(?P<label>[\w-]{,50})/$', views.discussion_forum, name='discussion_forum'),
url(r'^(?P<label>[\w-]{,50})/$', views.statementlist, name='statementlist'),
]
/forum/views.py def discussion_forum() is used to load all the information when the user first arrives at this forum.
I guess my problem might be that 1) the AJAX is wrong; 2) the url is wrong so that the updatestatementlist() can not be called.
Can anyone help me with that? Thanks a lot! Let me know if you need any other information!
Packages related:
Django==1.9.3
django-mptt==0.8.7
On the client side, Set your request header to X-Requested-With to XMLHttpRequest, Django use this specific header to determine whether it is a Ajax Request:
Here is the a snippet from Django source code:
https://docs.djangoproject.com/en/2.2/_modules/django/http/request/#HttpRequest.is_ajax
def is_ajax(self):
return self.META.get('HTTP_X_REQUESTED_WITH') == 'XMLHttpRequest'
After defining this header, you need to add one logic layer into your view function.
def your_view_func(request, *args, **kwargs):
if request.is_ajax():
...
return render(request, <your_ajax_template>)
return render(request, <your_normal_template>)
Updated:
I prefer the raw XMLHttpRequest API, if you use Jquery, add the berforeSend property.
$.ajax({
type: "GET",
beforeSend: function(request) {
request.setRequestHeader("X-Requested-With", "XMLHttpRequest");
},
...
});
Why X-Requested-With but not HTTP_X_REQUESTED_WITH?
HTTP headers in the request are converted to META keys by converting all characters to uppercase, replacing any hyphens with underscores and adding an HTTP_ prefix to the name.
https://docs.djangoproject.com/en/2.2/ref/request-response/#django.http.HttpRequest.META

Django - Ajax without JQuery lib

I am Learning and using Ajax without jQuery Lib. I created a simple view which renders a random number on to the template. I added a button and called the ajax function. However, clicking the button doesn't change the value on the screen. I checked in DOM (firebug) and it shows the someText.responseText is yielding the whole html rather than just the value, however it has the new value in that HTML. I am sharing this to provide more information on what I have found so far. I am new to this and experimented it with a lot for ex; I have checked "request.is_ajax():" but somehow the view does not find ajax in request. I have printed request on command line and the GET querydict is empty.
Obviously I am not doing something in the correct manner for Django. Please assist.
I have a view;
def home(request):
rand_num = random.randint(1,100)
return render(request, 'home.html', {'rand_num':rand_num})
and html and script;
<html>
<head>
<script type='text/javascript'>
var someText;
function helloWorld(){
someText = new XMLHttpRequest();
someText.onreadystatechange = callBack;
someText.open("GET", "{% url 'home' %}", true);
someText.send();
};
// When information comes back from the server.
function callBack(){
if(someText.readyState==4 && someText.status==200){
document.getElementById('result').innerHtml = someText.responseText;
}
};
</script>
</head>
<body>
<div id="result">{{rand_num}}</div>
<input type='button' value='Abraca dabra!' onclick="helloWorld()"/>
</body>
</html>
here is the url for this view;
url(r'^$', 'socialauth.views.home', name='home'),
I am learning this from an online tutorial.
That is because your AJAX endpoint is the whole view - I.e. your AJAX request asks for the whole rendered template.
What you want is just a number, so make a new view and URL to return just the number, and make the AJAX request to that.
AJAX isn't anything special, its just a way to make an asynchronous request to a URL and get the contents returned.
For reference, a view using something like JSONResponse:
from django.http import JsonResponse
def get_random_number_json(request):
random_no = random.randint(1,100)
return JsonResponse({'random_no': random_no})
Then in your frontend Javascript, fetch url for that view, which will give you only the JSON in your javascript variable via your AJAX call, and instead of all that document.getElementById('result') processing, you can just grab the variable from the json object.

Having trouble handling AJAX with Django Class Based View

I've been trying to switch my codes from Django function based view to class based view, but I'm having trouble understanding how to handle AJAX in Django CBV.
For example, suppose that I have this live search feature in my Django blog project.
(sorry, I tried to make it as simple as possible.)
urls.py
url(r'^search/$', search_page),
forms.py
class SearchForm(forms.Form):
query = forms.CharField()
entire_search_page.html
<form id="search-form" method="get" action=".">
{{form.as_p}}
<input type="submit" value="search" />
</form>
<div id="search-results">
{% include "just_the_result.html" %}
</div>
just_the_result.html
{% for post in post_list %}
<li>{{ post.title }}</li>
views.py
def search_page(request):
form = SearchForm()
post_list = []
if 'query' in request.GET:
form = SearchForm({'query': query})
post_list = Post.objects.filter(title__icontains=query)
if request.GET.has_key('ajax'):
variables = RequestContext(request, {
'post_list': post_list,
})
return render_to_response('just_the_result.html', variables)
else:
variables = RequestContext(request, {
'form': form,
'post_list': post_list,
})
return render_to_response('entire_search_page.html', variables)
search.js
$(document).ready(function() {
$("#search-form").submit(search_submit);
});
function search_submit() {
var query = $("#id_query").val();
$("#search-results").load(
"/search/?ajax&query=" + encodeURIComponent(query)
);
return false;
}
So basically, I'm showing the entire search page when the request is normal, while only showing the "just_the_result.html" if the request is AJAX. This works fine when I run the server, but I want to change this view to Class Based View.
This is what I have so far:
views.py
class PostSearch(ListView):
model = Post
template_name = 'app_blog/search.html'
context_object_name = 'post_list'
def get_queryset(self):
queryset = super(PostSearch, self).get_queryset()
query = self.request.GET.get('query')
if query:
return queryset.filter(title__icontains=query)
else:
return queryset
I guess this works correctly when the request is normal. However, I have no idea what to do when the request is an AJAX request! In the function based view, I could just return different templates and variables depending on whether the request is AJAX or not, but I don't think this is necessary or even possible in CBV. Also, one more question. I've been reading about RESTful design lately. Is my code above considered as "RESTful"?? I have trouble understanding how REST API is used exactly.
There are a lot of solutions to this problem, just search around:
http://django-braces.readthedocs.org/en/latest/other.html#ajaxresponsemixin
https://docs.djangoproject.com/en/1.5/topics/class-based-views/mixins/#more-than-just-html
Using Django class-based views, how can I return a different template if request.is_ajax

How do I include Django 1.2's CSRF token in a Javascript-generated HTML form?

I recently upgraded to Django 1.2.3 and my upload forms are now broken. Whenever I attempt to upload, I receive a "CSRF verification failed. Request aborted." error message.
After reading Django's documentation on this subject, it states that I need to add the {% csrf_token %} template tag within the HTML <form> in my template. Unfortunately, my <form> is generated via JavaScript (specifically, ExtJs's "html" property on a Panel).
Long story short, how do I add the required CSRF token tag to my <form> when my <form> is not included in a Django template?
Another option would be to adapt the cookie/header based solution shown in the Django docs with Ext - preferable if you have a lot of templates and don't want to change every single one.
Just drop the following snippet in your overrides.js (or wherever you put global modifications):
Ext.Ajax.on('beforerequest', function (conn, options) {
if (!(/^http:.*/.test(options.url) || /^https:.*/.test(options.url))) {
if (typeof(options.headers) == "undefined") {
options.headers = {'X-CSRFToken': Ext.util.Cookies.get('csrftoken')};
} else {
options.headers.extend({'X-CSRFToken': Ext.util.Cookies.get('csrftoken')});
}
}
}, this);
(edit: Ext already has cookie reading function, no need to duplicate it)
The easiest way is to create a hidden form on your page using django that doesn't do anything. Then use JavaScript to fetch the form and specifically the token input out of the form. Lastly, insert or copy that token input into the form you are dynamically generating.
Here are two examples of how you might publish the token for JavaScript.
<input id="csrf_token" value="{{ csrf_token }}"/>
<script type="text/javascript">
var CSRF_TOKEN = document.getElementById('csrf_token').value;
</script>
or
<script type="text/javascript">
var CSRF_TOKEN = "{{ csrf_token }}";
</script>
A better solution is to generate the code of the js file from a view/template.
Then, in the view you can set the csrf token up in the context like so...
from django.core.context_processors import csrf
context = RequestContext(request)
context.update(csrf(request))
Then, in the template, you can use {{ csrf_token }} to get the raw value of the csrf token, and then use that to build a hidden field into your form with the name csrfmiddlewaretoken.
Does the view you are POSTing to also respond to GET? In that the JS code can make a GET request to the view in question and parse the output to extract the CSRF token. My JS-fu is weak and I am not sure how best you can do the parsing from the client side.
For a broadly related example see this question. In this case the user was attempting to POST using a Python script and failing for the same reason. The solution was the same, except he had to do it from a Python script rather than JavaScript.
This may not be ideal, but it was the fastest solution for me. In my main template at the bottom of the "body", I added a javascript function to my library.
<script type="text/javascript">
MyToolkit.Utils.getCSRFToken = function () {
return "{% csrf_token %}";
};
</script>
This will use the csrf token or auto generate a new one if needed. It will handle all form submits on the page. If you have off-site forms you'll need to make sure they don't run this code.
<script>
$(document).on('submit', 'form[method=post]', function(){
if(!document.cookie.match('csrftoken=([a-zA-Z0-9]{32})')) {
for(var c = ''; c.length < 32;) c += 'abcdefghijklmnopqrstuvwxyz'.charAt(Math.random() * 26)
document.cookie = 'csrftoken=' + c + '; path=/'
}
if(!this.csrfmiddlewaretoken) $(this).append('<input type="hidden" name="csrfmiddlewaretoken">')
$(this.csrfmiddlewaretoken).val(document.cookie.match('csrftoken=([a-zA-Z0-9]{32})')[1])
})
</script>
requires jQuery 1.7+

Categories

Resources