How to write a Django view for a POST request - python

I have written a very small example: a junit button which sends a POST request with a pair of values:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>jQuery UI Button - Default functionality</title>
<script src="{{STATIC_URL}}js/jquery-1.9.1.js"></script>
<script src="{{STATIC_URL}}js/jquery-ui-1.10.3.custom.js"></script>
<link rel="stylesheet" href="{{STATIC_URL}}css/jquery-ui-1.10.3.custom.css">
<script>
$(function() {
$( "button" )
.button()
.click(function( event ) {
var postdata = {
'value1': 7,
'value2': 5
};
$.post('', postdata); // POST request to the same view I am now
window.alert("Hello world!"); // To know it is working
});
});
</script>
</head>
<body>
<button>Submit</button>
</body>
</html>
So, the view is rendered when a GET request is sent to localhost:8000/button/, and when the button is pushed a POST request is also sent to localhost:8000/button/.
urls.py
from django.conf.urls import patterns, url
urlpatterns = patterns('',
url(r'^button/$', 'helloworld.views.buttonExample'),
)
views.py
def buttonExample(request):
print 'RECEIVED REQUEST: ' + request.method
if request.method == 'POST':
print 'Hello'
else: #GET
return render(request, 'buttonExample.html')
When the GET request is done, the view is displayed correctly and I can also read at Django console the lines:
RECEIVED REQUEST: GET <---- This line is because of my print
[28/May/2013 05:20:30] "GET /button/ HTTP/1.1" 200 140898
[28/May/2013 05:20:30] "GET /static/js/jquery-1.9.1.js HTTP/1.1" 304 0
[28/May/2013 05:20:30] "GET /static/js/jquery-ui-1.10.3.custom.js HTTP/1.1" 304 0
[28/May/2013 05:20:30] "GET /static/css/jquery-ui-1.10.3.custom.css HTTP/1.1" 304 0
...
And when the button is pushed, I can see:
[28/May/2013 05:20:34] "POST /register/ HTTP/1.1" 403 142238
But "RECEIVED REQUEST: POST" is never printed. Neither is "Hello". It seems like the urls.py is not serving the view when a POST arrived, because in Firebug I can see that POST status is 403 FORBIDDEN.
This is probably a silly newbie mistake, but I don't know what am I missing. I have read the django book chapter about advanced URLConf and Views, and it looks like it should work just by checking request.method value.

This is by design. Your POST data must contain csrfmiddlewaretoken value. You can get it from your cookies and then send it with POST requests. Details here. For your specific case, you can do this -
<script>
$(function () {
function getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie != '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = jQuery.trim(cookies[i]);
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) == (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
var csrftoken = getCookie('csrftoken');
$("button")
.button()
.click(function (event) {
var postdata = {
'value1': 7,
'value2': 5,
'csrfmiddlewaretoken': csrftoken
};
$.post('', postdata); // POST request to the same view I am now
window.alert("Hello world!"); // To know it is working
});
});
</script>

You are receiving a 403 because of CSRF protection - you have not provided a token to protect yourself from attacks. The documentation tells you all you need to know.

Related

want to be able to do the post method and display the data in the table field

currently when i submit the function first takes me to the api page where i have to click on post again for the results to update in the database then click on back button and refresh the page to see the updated data, it will be nice if the reduce button could update and display the data on the table without redirecting to the api page. Thank You, Please Help. trying to render the data here
#api_view(['POST'])
def sRd(request, pk):
sw = get_object_or_404(Swimmers,id=pk) # gets just one record
current_sessions = sw.sessions + 10
sw.sessions = current_sessions # updates just the one in memory field for sw (for the one record)
sw.save() # you may want to do this to commit the new value
serializer = SubSerializer(instance=sw, data=request.data)
if serializer.is_valid():
serializer.save()
return JsonResponse(serializer.data, safe=False, status=status.HTTP_201_CREATED)
return JsonResponse(data=serializer.errors, safe=False, status=status.HTTP_400_BAD_REQUEST)
Want to render the data here on this page:
return render(request, 'accounts/modals/swimming/_vw_table.html', {'sw': sw})
The solution was to use Ajax asynchronous to be able to process data on the backend and display the results on the frontend using jQuery or any of the frontend framework. You must also include a csrf token or exempt it using #csrf_token by adding the plugin
from django.views.decorators.csrf import csrf_protect
<script type="text/javascript">
// CSRF TOKEN //
function getCookie(name) {
let cookieValue = null;
if (document.cookie && document.cookie !== '') {
const cookies = document.cookie.split(';');
for (let i = 0; i < cookies.length; i++) {
const cookie = cookies[i].trim();
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
const csrftoken = getCookie('csrftoken');
//Post Button Working With View Function sRd
$(document).ready(function () {
$("#post-form").submit(function (event) {
event.preventDefault();
$.ajax({
headers: {
'Content-type':'application/json',
'X-CSRFToken': csrftoken,
},
url: "{% url 'srd' srd.pk %}",
type: "POST",
data: $('#post-form').serialize(),
success: function (data) {
console.log(data);
}
}); // end ajax
});
});
</script>

DeleteView not working with Ajax and Bootbox in Django

I'm using Bootbox along with Ajax to delete a listing in my app which is calling a DeleteView but after I confirm the deletion, nothing changes.
View.py
class FileDelete(DeleteView):
model = Uploaded
success_url = reverse_lazy('index')
template_name = 'FileManagement/delete_file.html'
Script
<script>
$(".delete-file").click(function () {
var button = $(this);
var id = button.attr("data-id");
console.log(id);
bootbox.confirm("Are you sure you want to delete this file?",
function (result) {
if (result) {
$.ajax({
method: "GET",
url: "delete/" + id,
success: function(){
}
});
}
});
});
</script>
Urls.py
url(r'^delete/(?P<pk>\d+)/$', views.FileDelete.as_view(), name="delete_file")
I haven't finished the success part but it's still not deleting from the database.
You should use POST request instead of GET. Reference
Also, do not forget to include csrf_token.
<script>
$(".delete-file").click(function () {
var button = $(this);
var id = button.attr("data-id");
console.log(id);
bootbox.confirm("Are you sure you want to delete this file?", function (result) {
if (result) {
data = {
csrfmiddlewaretoken: "{{ csrf_token }}",
id: id
}
var posting = $.post("{% url 'delete_file' %}", data);
posting.done(function (data) {
// done
});
posting.fail(function (data) {
// fail
});
}
});
});
</script>

Adding Ajax to Django

I have a simple messaging system built in my Django project. Currently, a user needs to refresh the page to see the new messages. How do I add Ajax to load the messages asynchronously?
View:
def user_messages(request):
time_now = datetime.datetime.now()
user = request.user
if request.method == "POST":
sender = request.user
receiver_name = request.POST.get('msg_receiver')
receiver = User.objects.get(username=receiver_name)
msg_content = request.POST.get('msg_content')
Messages.objects.create(sender=sender, receiver=receiver, msg_content=msg_content)
inbox = Messages.objects.filter(receiver=user).order_by('-timestamp')
outbox = Messages.objects.filter(sender=user).order_by('-timestamp')
context = {'inbox': inbox, 'outbox': outbox, 'time_now': time_now}
return render(request, 'accounts/messages.html', context)
Messages.html:
<h6>Inbox</h6>
{% for message in inbox %}
<ul>
<li title="{{ message.sender.username }}">{{ message.sender.first_name }}: {{ message.msg_content }}
<button onclick="myFunction()">Reply</button>
</li>
<small>-{{ message.timestamp }}</small>
<hr>
</ul>
{% endfor %}
You can create a Javascript file in the static folder to do this.
As you are sending a POST request, you need to include the CSRF token in order to do this process in a secure manner. Check on Django's documentation for more details. This first function get the CSRF token from the cookies:
getCookie(name) {
let cookieValue = null;
if (document.cookie && document.cookie !== '') {
let cookies = document.cookie.split(';');
for (let i = 0; i < cookies.length; i++) {
let cookie = cookies[i].trim();
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
This is the Ajax code for sending/receiving data, just vanilla Javascript. The same code would load the previous messages when the user loads the page for the first time, after x seconds (to display messages if someone else sends a message) or after the user sends a message:
requestAjax(data) {
// Gets the CSRF token using the previous function
let csrftoken = getCookie('csrftoken');
// Initiate new AJAX request
const request = new XMLHttpRequest();
request.open('POST', '/add-messages/', true);
// Set request header with CSRF token code
request.setRequestHeader('X-CSRFToken', csrftoken);
request.setRequestHeader('contentType', 'application/json; charset=utf-8');
// Callback function for when the request completes
request.onload = () => {
// The server returns a request object
const serverResponse = JSON.parse(request.responseText);
// The request object includes a 'success' key with a boolean value to indicate if the request was successful or not
if (serverResponse.success) {
// If 'success' is true, display the received messages
}
else {
// If 'success' is false, there is a server side error, display error message
}
}
// Sends msg_receiver and msg_content to server
request.send(JSON.stringify(data));
}

How do I get data from my AJAX Post to my Django View?

This is what My ajax call looks like
$.ajax({
url:"{% url 'handsontable' %}",
data: {'getdata': JSON.stringify(hot.getData())},
dataType: 'json',
type: 'POST',
success: function (res, status) {
alert(res);
alert(status);
},
error: function (res) {
alert(res.status);
}
});
This is what my django view looks like.
if request.method == 'POST':
request_getdata = request.POST.get('getdata', 'None')
return HttpResponse(request_getdata)
The alerts in ajax return the data and "success". But my HttpResponse returns "None".
Any idea why it is not passing the data through? Thanks!
First off you are trying to POST to a html file
url:"/utility_tool/decisions/solution_options/handsontable.html",
Instead, it should be a url to a view.
Second, the ajax post request should have the csrftoken in it's header and you can set it up like this:
<script type="text/javascript">
// using jQuery get csrftoken from your HTML
var csrftoken = jQuery("[name=csrfmiddlewaretoken]").val();
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
beforeSend: function (xhr, settings) {
// if not safe, set csrftoken
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});
$.ajax({
url: "{% url 'name of the view from urls.py' %}",
data: {
// here getdata should be a string so that
// in your views.py you can fetch the value using get('getdata')
'getdata': JSON.stringify(hot.getData())
},
dataType: 'json',
success: function (res, status) {
alert(res);
alert(status);
},
error: function (res) {
alert(res.status);
}
});
</script>
And in your django view:
# views.py
from django.http import JsonResponse
def someView(request):
if request.method == 'POST':
# no need to do this
# request_csrf_token = request.POST.get('csrfmiddlewaretoken', '')
request_getdata = request.POST.get('getdata', None)
# make sure that you serialise "request_getdata"
return JsonResponse(request_getdata)
And in your urls:
# urls.py
urlpatterns = [
# other urls
path('some/view/', views.someView, name='name of the view in urls.py'),
]
I cannot add comments because I do not yet have up to 50 reputations as demanded by StackOverflow. This is supposed to be a comment under the answer provided by #abybaddi009. He has done a very good job thus far but the answer needs a finishing touch.
In the view
request_getdata = request.POST.get('getdata', None) does not work
but this does
body = request.body.decode('utf-8')
data = body[3]
request.body.decode('utf-8') returns a string which would look something like getdata=your_data you can then use string manipulation techniques or regex to extract your data.
What you need to do is :
code for ajax call ( in js file) to send the data to the view
jQuery.ajax(
{
'url': "url_pattern_in_urls_py_file/",
'type': 'POST',
'contentType': 'application/json; charset=UTF-8',
'data': JSON.stringify({'updated_data':your_data_val}),
'dataType': 'json',
'success': function ( return_data ) {
//success body
}
}
);
code in django view with respect to above POST ajax call to receive the data
import json
if request.method == 'POST':
updatedData=json.loads(request.body.decode('UTF-8'))
I added return false; at the end of the ajax request and it worked. I printed out the values in the view instead of using HttpResponse.

Using django url in Ajax is returning a string

When using {% url 'query' %} inside an AJAX get call is returning a string but when I put a static url it works properly.
I'm using Django-Filters and Django-rest-framework in installed apps.
url.py
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^query/$', 'my_app.views.app_function', name='query')
]
app.js
$(document).ready(function(){
// LOAD COOKIE
function getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie != '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = jQuery.trim(cookies[i]);
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) == (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
var csrftoken = getCookie('csrftoken');
function callServer () {
$.ajax({
type: 'GET',
url: "{% url 'query' %}",
success: function (json) {
console.log(json)
},
error: function(x, t, m) {
if(t==="timeout") {
alert("got timeout");
} else {
alert(t);
}
},
headers: {
'X-CSRFToken': csrftoken
}
});
}
$("#query").click(function () {
$('#sub').submit(function (e) {
e.preventDefault();
});
return callServer();
});
});
views.py
class AppFilter(django_filters.FilterSet):
class Meta:
model = Post
fields = ['first', 'second']
#api_view(['GET'])
def app_function(request):
qs = Post.objects.all()
f = AppFilter(request.GET, queryset=qs)
serializer = PostSerializer(f, many=True)
return Response(serializer.data)
forms.py
class QueryForm(forms.Form):
first = forms.TypedChoiceField(
widget=forms.Select,
choices=choice_dict1
)
second = forms.TypedChoiceField(
widget=forms.Select,
choices=choice_dict2
)
Any help before I burn the place?
Django would not be able to resolve {% url 'query' %} in JS file, since that's client side stuff. reverse url is resolved at the time of html file rendering.
What you can do is, pass that url as init() function of that JS module from html file:
<!-- In your Template file -->
<script>
$(function(){
app.init("{% url 'query' %}");
});
</script>
And export the app module from js file. Set that url as a variable, and use it in ajax call.
The problem is that your javascript file (app.js) is probably not the template. You don't show it, but I assume you have an HTML file that is loading the app.js file. The HTML file is where the template variables and such will get expanded. The simplest way to resolve this is to embed the javascript code into your HTML file inside a <script> tag.
There is a library for Flask called Flask-JSGlue that solves this problem and lets you use template variables in your javascript files, but I cannot find a similar library for Django.

Categories

Resources