http 403 error with django and ajax - ajax

I'm working my way through 'Django 1.0 Web Site Development' and encountered a problem when using forms. The server complained about something concerning 'csrf'. I could solve it by adding {% csrf_token %} right after the form-tag. I already read the documentation at djangoproject.com but I have to admit that I don't fully understand what exactly is happening here. I don't use the middleware classes.
The real problem started when I got to ajax. I followed the instructions in the book to the letter but the server started complaining:
"POST /save/?ajax HTTP/1.1" 403 2332
Here is the code that might cause the trouble:
function bookmark_save() {
var item = $(this).parent();
var data = {
url: item.find("#id_url").val(),
title: item.find("#id_title").val(),
tags: item.find("#id_tags").val()
};
$.post("/save/?ajax", data, function (result) {
if (result != "failure") {
item.before($("li", result).get(0));
item.remove();
$("ul.bookmarks .edit").click(bookmark_edit);
}
else {
alert("Failed to validate bookmark before saving.");
}
});
return false;
}
'/save/&ajax' is being handled by
if ajax:
return render_to_response('bookmark_save_form.html', variables)
Here the bookmark_save_form.html:
<form id="save-form" method="post" action="/save/">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="save" />
</form>
As far as I understand things, I have to pass a csrf_token with the POST request. But I don't have a clue how.
Any advise on this would be great.

I am currently working through this book as well and ran into the exact same problem, BTW. Not for the first time either! Essentially what is happening is that the csrf token is not being passed via the Ajax request. So, the short and simple answer is that you need to include the csrf token is your ajax call. This is accomplished via this code block: https://docs.djangoproject.com/en/1.3/ref/contrib/csrf/#ajax
jQuery(document).ajaxSend(function(event, xhr, settings) {
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;
}
function sameOrigin(url) {
// url could be relative or scheme relative or absolute
var host = document.location.host; // host + port
var protocol = document.location.protocol;
var sr_origin = '//' + host;
var origin = protocol + sr_origin;
// Allow absolute or scheme relative URLs to same origin
return (url == origin || url.slice(0, origin.length + 1) == origin + '/') ||
(url == sr_origin || url.slice(0, sr_origin.length + 1) == sr_origin + '/') ||
// or any other URL that isn't scheme relative or absolute i.e relative.
!(/^(\/\/|http:|https:).*/.test(url));
}
function safeMethod(method) {
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
if (!safeMethod(settings.type) && sameOrigin(settings.url)) {
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
}
});
I then included this as a .js file in my user_page.html. After that, I could make Ajax calls with impunity!

I pulled this from a project already done. This is a contact form template. Mind you this is for django. Also please refer to the django book http://www.djangobook.com/en/2.0/ . All my questions have been answered by this book. It goes over everything. This shows exactly how to put in the csrf token (in a template):
<head>
<title>Contact Us</title>
</head>
<body>
<h1>Contact us</h1>
{% if form.errors %}
<p style="color: red;">
Please correct the error{{ form.errors|pluralize }} below.
</p>
{% endif %}
<form action="" method="post">
{% csrf_token %}
<ul>
{{ form.as_ul }}
</ul>
<input type="submit" value="Submit">
</form>
</body>
Also, change your value to submit instead of save, and instead of /save/ for action use post.....that might make it work.

I am working through the book and just ran into the same problem. Here is the simplest solution, which has the benefit of not disabling Django's csrf protection or having to include decorators or fiddle with utilities like 'ensure_csrf_cookie'. It simply passes the token:
In the .js file you created to hold your custom jquery scripts, add the following pair to your 'data' var in in your bookmark_save() function:
csrfmiddlewaretoken: document.getElementsByName('csrfmiddlewaretoken')[0].val()
So the resulting bookmark_save function looks like this:
function bookmark_save() {
var item = $(this).parent();
var data = {
url: item.find("#id_url").val(),
title: item.find("#id_title").val(),
tags: item.find("#id_tags").val(),
csrfmiddlewaretoken: document.getElementsByName('csrfmiddlewaretoken')[0].val()
};
$.post("/save/?ajax", data, function (result) {
if (result != "failure") {
item.before($("li", result).get(0));
item.remove();
$("ul.bookmarks .edit").click(bookmark_edit);
}
else {
alert("Failed to validate bookmark before saving.");
}
});
return false;
}

from django.views.decorators.csrf import csrf_exempt
#csrf_exempt
def my_view(request):
...

Create a Javascript file. I do not know how to format the code - sorry. Then load it after Jquery.
It is described here

Related

I am not sure if my Vue code is efficient

I am a beginner in Vue and I am wondering if I can get an insight from experienced developers here about my Vue codes. I just want to ask for help to know if my Vue approach is efficient and proper. (Project is running on Laravel)
The Case:
Let us say I have 2 tables in DB
(1) stores
(2) ad_accounts
Then we have 2 web pages to present these tables' data and execute CRUD functions with it
(1) store.blade.php
(2) adaccount.blade.php
Each page is running a Vue component
(1) Stores.vue
(2) AdAccounts.vue
I am using Vuex for store management.
Within store.js, I would have set of actions for CRUD for each vue component.
Now I realized that I have series of actions that actually does the same thing. For example, I have an action to add stores, and another action to add Ad accounts. Their only difference is that they are calling a different Laravel route.
So it seemed to me that my code was unnecessarily long and a bit expensive. To resolve, I decided to write my actions in a form of template. So this is what I did:
In store.js, I created an action for each CRUD function to be used as template
In Stores.vue and AdAccounts.vue, if I need to execute a CRUD function, I would use a method to call the corresponding action from store.js and provide the Laravel route as part of the action's payload
I have states and corresponding getters for returning these states in Stores.vue and AdAccounts.vue
Each action has a dedicated mutation that alters the approriate state
states and getters are mapped in each Vue component in order to access and use them
Is this approach efficient and proper? I have sample methods and actions below for reference.
Stores.vue
<template>
<div>
<form #submit.prevent="addData('stores/add')">
<button type="submit" class="btn btn-primary">Save</button>
</form>
</div>
</template>
<script>
export default {
methods: {
addData: function(url) {
this.payload.url = url
if(
this.payload.requestData.store_name == "" &&
this.payload.requestData.store_token == ""
) {
this.payload.isErr = true;
this.payload.errMsg = "ERROR: Could not continue due to some invalid or missing data. \nPlease check your entries and try again or contact your administrator.";
this.$store.dispatch('addData', this.payload)
}
else {
this.payload.isErr = false;
this.$store.dispatch('addData', this.payload)
this.readDataAll('stores/all', 'store');
}
this.cleanOnModalDismiss(this.$refs.addModal, this.refreshRequestData)
}
}
}
</script>
AdAccounts.vue
<template>
<div>
<form #submit.prevent="addData('ad_accounts/add')">
<button type="submit" class="btn btn-primary">Save</button>
</form>
</div>
</template>
<script>
export default {
methods: {
addData: function(url) {
this.payload.url = url
if(
this.payload.requestData.ad_id == "" &&
this.payload.requestData.ad_name == ""
) {
this.payload.isErr = true;
this.payload.errMsg = "ERROR: Could not continue due to some invalid or missing data. \nPlease check your entries and try again or contact your administrator.";
this.$store.dispatch('addData', this.payload)
}
else {
this.payload.isErr = false;
this.$store.dispatch('addData', this.payload)
this.readDataAll('ad_accounts/all', 'adaccounts');
}
this.cleanOnModalDismiss(this.$refs.addModal, this.refreshRequestData)
}
}
}
</script>
store.js
export default new Vuex.Store({
actions: {
addData (commit, payload) { // insert a record to DB
try {
if(payload.isErr == true) {
commit('SHOW_ERRORS', {messageType: "alert-danger", errorMessage: payload.errMsg});
} else {
axios.post(payload.url, payload.requestData)
.then(response=>{
if(response.status == 200) {
var err_msg = "";
if(response.data.success !== null) {
response.data.messageType = "alert-info"
response.data.actionMessage = response.data.success
commit('ADD_DATA', response.data);
} else {
response.data.messageType = "alert-danger"
for(var i=0; i<response.data.error.length; i++) {
err_msg += response.data.error[i] + "\n"
}
response.data.actionMessage = err_msg
commit('ADD_DATA', response.data);
}
}
else {
commit('SHOW_ERRORS', {messageType: "alert-danger", errorMessage: "ERROR: Connection status set to '" + response.headers.connection + "' due to error " + response.status + " " + response.statusText + ". \nPlease contact your administrator."});
}
})
}
} catch (error) {
commit('SHOW_ERRORS', {messageType: "alert-danger", errorMessage: error})
}
}
}
}

Ajax call not returning a response, just reloads page

I have a Symfony 3 CRM and I use ajax calls to action the removal of items throughout the system. It uses a single call and then uses a switch statement to determine what it is the user is attempting to delete and handles it accordingly.
However, for some strange reason one particular type of item doesn't seem to work, it just reloads the page.
Here is the trigger button (I am implementing bootstrap confirmation):
<a href="" data-type="unit" id="{{ unit.id }}"
data-toggle="confirmation-singleton"
data-btn-ok-class="btn btn-xs btn-success"
data-btn-cancel-class="btn btn-xs btn-danger"
class="btn btn-xs btn-danger remove-item">
<i class="fa fa-remove no-override"> </i>
</a>
My ajax call for removal of items:
$('.remove-item').confirmation({
rootSelector: '[data-toggle=confirmation-singleton]',
container: 'body',
onConfirm: function() {
var type = $(this).attr('data-type');
var id = $(this).attr('id');
var data = type + '|' + id;
$.ajax( '/app_dev.php/ajax-call/remove-item/' + data )
.done( function(response) {
if(response != 'success') {
if(response == 'units_exist') {
alert("You cannot delete this item as there are units already linked to it.");
} else if(response == 'no_property') {
alert("Sorry! Property could not be found.");
} else if(response == 'bookings_exist') {
alert("Sorry! This unit has bookings. Please delete the bookings first.");
}
}
});
return false;
},
onCancel: function() {
return false;
}
});
And on the PHP side, for this particular example:
$data = $request->get('data');
$parts = explode("|",$data);
$type = $parts[0];
$id = $parts[1];
// using switch on $type
case 'unit':
$em = $this->getDoctrine()->getManager();
$repo = $em->getRepository('AppBundle:Unit');
$booking_repo = $em->getRepository('AppBundle:Booking');
$bookings = $booking_repo->findBy(array('unitId' => $id)); // check to see if any bookings exist
if(!empty($bookings)) {
return new Response('bookings_exist');
} else {
$item = $repo->findOneBy(array('id' => $id));
if(!empty($item)) {
$em->remove($item);
$em->flush();
}
}
break;
In this example, it SHOULD return 'bookings_exist' and if I directly go to the URL in the browser, it does display this message - however, all it does it reload the page instead of throwing the alert as stipulated in the ajax call. I know this call works as it does successfully delete other items in the CRM, it just seems to be when it cannot delete it due to a condition such as this.
I may be missing something really obvious here, so any help is appreciated.
For jQuery Ajax, use success and error handlers
Other handlers in jQuery's Ajax object are unreliable at best, and vary in their behavior and support between versions and browsers.
Prevent Default is generally a good idea with ajax handled events
Should jQuery fail, and NOT return false, the element will do it's default behavior, which in your case is which reloads the page.
onConfirm: function(e) {
e.preventDefault();
var type = $(this).attr('data-type');
var id = $(this).attr('id');
var data = type + '|' + id;
$.ajax( '/app_dev.php/ajax-call/remove-item/' + data )
.success( function(response) {
if (response.errorMessage) {
alert(response.errorMessage);
}
})
.error( function(xhr, status, error) {
console.log(status + '\n' + error);
})
;
return false;
}
PHP Side, build a JSONResponse
if(!empty($bookings)) {
return new JsonResponse([
'errorMessage' => 'Sorry! Property could not be found.'
);
}
instead of just adding .done() you should also use
.fail(function( jqXHR, textStatus, errorThrown ) {});
to catch any errors.
If the bookings is not empty then the function will return the new response 'booking_exist' and stop ... it will not proceed to next statments .
So if you need to delete the item use this code instead :
if(empty($bookings)) {
return new Response('bookings_not_exist');
} else {
$item = $repo->findOneBy(array('id' => $id));
if(!empty($item)) {
$em->remove($item);
$em->flush();
}

django forms ajax get client's data from db

Hello im trying to fill the field "amount" that cointains the price of the payment_plan, and the payment_plan is part of the client information. I've been searching and the way to do it is implementing Ajax, but i have not found an example with django forms, every solution is really diferent from mine.
this is the model:
class Payment_Plans(models.Model):
name = models.CharField(max_length=20, primary_key=True)
price = models.IntegerField(default='0')
def __unicode__(self):
return self.name
class Clients(models.Model):
id = models.IntegerField(max_length=10, primary_key=True, default=0)
payment_plan = models.ForeignKey(Payment_Plans, null=True)
def __unicode__(self):
return self.id
class Payments(models.Model):
client = models.ForeignKey(Clients)
month_from = models.DateField(default='1111-01-01')
month_to = models.DateField(default='1111-01-01')
amount = models.IntegerField(default='0')
def __unicode__(self):
return self.month_from.strftime('%Y-%m-%d')
this is my payment form:
class PaymentsForm(forms.ModelForm):
month_from = forms.DateField(widget=DateTimePicker(options={"format": "YYYY-MM-DD", "pickTime": False}), label="Mes desde")
month_to = forms.DateField(widget=DateTimePicker(options={"format": "YYYY-MM-DD", "pickTime": False}), label="Mes Hasta")
amount = forms.IntegerField(label="Monto")
client = forms.ModelChoiceField(queryset=Clients.objects.all(), label="Cliente")
class Meta:
model=Payments
fields = ('month_from', 'month_to', 'amount', 'client')
This is the template:
{% extends 'base.html' %}
{% load bootstrap %}
{% block titulo %}Realizar Pago{% endblock%}
{% block encabezado %}
<h1>Realizar Pago</h1>
<!-- Para el datepicker -->
{{ form.media }}
{% endblock%}
{% block contenido %}
<form id='form' method='POST' action=''>{% csrf_token %}
<div class="col-sm-4">
</div>
<div class="col-sm-4">
{{ form.client|bootstrap }}
{{ form.month_from|bootstrap }}
{{ form.month_to|bootstrap }}
{{ form.amount|bootstrap }}
{{ form.days_left|bootstrap }}
<input type='submit' name='submit' value='Pagar' class="btn btn-default"/>
</div>
</form>
{% endblock%}
this should work like this:
1) the user selects the Client (right now its just a select box, in future autocomplete field)
2) the form should look into the client's payment_plan and then into the payment_plan price.
3) field should be filled with the price
how can i achive this? is it possible with django forms? shall i write manually the template instead of ussing tags like {{forms.client}}? if thats the case, how do i get the Clients?
You can use AJAX, you just need to know the fields' ids. Set an onchange (or .change() if you're using jquery) event on the 'client' field that sends the client id to a view, for instance, '/client-price' that will use it to query for the other price. Something like:
$( "#client" ).change(function() {
clientID = $(this).val();
$.ajax({
type: "GET", // if you choose to use a get, could be a post
url: "/client-price/?id=" + clientID,
success: function(data) {
$( "#amount" ).val(data.price);
});
The view/url would take the id. This post shows how you'd want to format your view to send back a json response.
Thanks onyeka! after some research with ajax and json the code looks like this:
view: (remember to import from django.http import JsonResponse)
def amount(request):
if request.method == 'GET':
total_amount = model.amount
response_data ={}
response_data['amount'] = total_amount
return JsonResponse(response_data)
ajax.js:
$(document).ready(function() {
$('#id_client').change(function(){
var query = $(this).val();
console.log(query);
$.ajax({
url : "/amount/",
type : "GET",
dataType: "json",
data : {
client_response : query
},
success: function(json) {
document.getElementById('id_amount').value=json.amount;
},
failure: function(json) {
alert('Got an error dude');
}
});
});
});
url.py
add corresponding line:
url(r'^amount/$', 'main.views.amount', name='amount'),

AJAX username validation in Django

I want to create asynchronous username validation,
where upon change of the value of the username input, the database is accessed to see if that username is valid for use. So far I have this code, which doesn't seem to work. Please help me in finding out where things went wrong. Thanks!
My HTML:
<div>Username</div>
<input type="text" name="id" id="id">
<div id="idval"></div>
My Script:
<script>
function CheckId() {
$.get('/signup/', {username: $(this).val()},
function(data){
if(data == "True"){
$('#idval').html("You may use this ID");
} else {
$('#idval').html("Unavailable");
}
});
}
function onChange(){
$("#id").change( function() {CheckId()});
}
$(document).ready(onChange);
</script>
My View:
def signup(request):
if request.method == "GET":
p = request.GET.copy()
if p.has_key('username'):
name = p['username']
if User.objects.filter(username__iexact=name):
return HttpResponse(False)
else:
return HttpResponse(True)
in CheckId() $(this).val() isn't going to work. You need $('#id').val()
See this discussion of how the this keyword works

Django Jquery Get URL Conf

Ok, so I'm trying to call the function
def user_timetable(request, userid):
user = get_object_or_404(TwobooksUser,id = userid)
timeSlots = TimeSlot.objects.filter(user = request.user)
rawtimeslots = []
for timeSlot in timeSlots:
newSlot = {
'userid': timeSlot.user.id,
'startTime': str(timeSlot.startTime),
'endTime': str(timeSlot.endTime),
}
rawtimeslots.append(newSlot)
return HttpResponse(simplejson.dumps(rawtimeslots))
through the javascript in
{% include 'elements/header.html' %}
<script type='text/javascript'>
$(document).ready(function() {
$.get('/books/personal{{ user.id }}/timetable/', {}, function(data) {
data = JSON.parse(data);
var events = new Array();
for (var i in data) {
events.push({
id: data[i].id,
title: '{{ request.user.name }}',
start: Date.parse(data[i].startTime, "yyyy-MM-dd HH:mm:ss"),
end: Date.parse(data[i].endTime, "yyyy-MM-dd HH:mm:ss"),
allDay: false
});
}
where the above exists in a template that's being rendered (I think correctly).
The url conf that calls the function user_timetable is
url(r'^books/personal/(?P<userid>\d+)/timetable/$',twobooks.ajax.views.user_timetable),
But, user_timetable isn't being called for some reason.
Can anyone help?
EDIT-
Ok the original problem was that the template was not being rendered correctly, as the url in firebug comes to '/books/personalNone/timetable/' , which is incorrect.
I'm rendering the template like this -
def renderTimetableTemplate(request):
#if request.POST['action'] == "personalTimetable":
user = request.user
return render_to_response(
'books/personal.html',
{
'user': user,
},
context_instance = RequestContext(request)
)
Is there a mistake with this?
There is a slash missing after "personal"
$.get('/books/personal{{ user.id }}/timetable/', {}, function(data) {
should be
$.get('/books/personal/{{ user.id }}/timetable/', {}, function(data) {
Btw. you should use the {% url %} template tag.
There is a mismatch between the data you're converting to JSON and passing to the script, and the data that the script is expecting. You are passing a userId element in each timeslot, whereas the script is expecting just id.
This error should have shown up in your browser's Javascript console, and would be even easier to see in Firebug (or Chrome's built-in Developer Tools).

Resources