Django - Ajax error while saving form values - django

I have an Edit Form page which edits existing posts. i wanted to put a Preview link into this page. what i want is ; when i click preview link it must ;
take form element's current values and write them into my
Post_Preview Model.
then , ajax function must redirect to my *show_preview* page which i defined in views and urls.
and in show_preview page (preview.html) it must be rendered. (form's
current values)
this is how it must works. And here are my codes :
and my edit-form page:
<form method="post" action="">
{% csrf_token %}
<input type="hidden" id="post_owner" value="{{ post.owner }}"/></td>
<input type="hidden" id="post_id" value="{{ post.id }}"> </td>
{{ form.title }}
{{ form.body }}
Preview
<input type="submit" value="Save" style="cursor: pointer;"/>
</form>
ajax Function:
$(function(){
$('#preview').click(function() {
var title = $('#id_title').val();
var body = $('#id_body').val();
var owner = $('#post_owner').val(); //hidden value at form page
var id = $('#post_id').val(); //hidden value at form page
var ajaxOptions = {
type:'post',
url : '/admin/post/save_preview/', //save_preview's url
data : {
'title' : title,
'body' : body,
'owner' : owner,
'id' : id
},
success: function(){
window.open("/blog/"+owner+"/preview/"+id); //show_preview's url
},
error: function(){
alert('There is an Error'); //this is what i see when click preview link.
}
};
$.ajax(ajaxOptions);
});
});
my save_preview view:
def save_preview(request):
title = request.POST['title']
body = request.POST['body']
owner = request.POST['owner']
post_id = request.POST['id']
try:
preview = Post_Preview(id=post_id, title=title, body=body, owner=owner)
preview.save()
except:
pass
return HttpResponse(200)
my show_preview view:
def show_preview(request,post_id,username):
preview = Post_Preview.objects.get(id=post_id)
return render_to_response('preview.html',{'post': preview}, context_instance=RequestContext(request))
my related url lines:
url(r'^admin/post/save_preview/', view='save_preview' ,name='save_preview'),
url(r'^blog/(?P<username>[-\w]+)/preview/(?P<post_id>\d+)', view='show_preview', name='show_preview'),
When i click Preview link at edit-form page : it shows 'There is an Error' error; which is defined in ajax function.
thank you!
edit : there is more code before my ajax function in js file (which are related to django-ajax relation ):
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 csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
function sameOrigin(url) {
// test that a given url is a same-origin 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));
}
$.ajaxSetup({
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type) && sameOrigin(settings.url)) {
// Send the token to same-origin, relative URLs only.
// Send the token only if the method warrants CSRF protection
// Using the CSRFToken value acquired earlier
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});
edit 2: when i add try/except blocks for save_preview ; i didnt throw popup error page. it redirected to save_preview page and threw and error :
Post_Preview matching query does not exist.
156. preview = Post_Preview.objects.get(id=post_id)

You're not sending the csrf token in $.ajax.

Related

Delete Specific Post from Front-end using ajax in Django (Class Based View)

I have lot of posts generated using loop in django, and want to delete specific post (like Facebook delete works). I am able to get id of post using jquery but i am not sure what I am doing wrong to delete post. I have also implemented delete function in class based view.
Delete Post Button
existing-dashboard.html
{% for i in all_posts %}
... ///rest of the code
<span class="username">{{ i.first_name }} {{i.surname}}
<span class="more" id="more-icon">{{i.post_id}}
<div class="more-menu" style="margin-top: 30px;">
<span class="delete" id="{{i.post_id}}">delete</span>
</div>
</span>
... /// rest of the code
</span>
{% endfor%}
Ajax
$('.delete').on('click', function(){
var post_id = $(this).attr('id');
alert(post_id)
$.ajax({
url: 'http://127.0.0.1:8000/existing-delete/' + post_id +'/',
type: 'DELETE',
data: {},
contentType: 'application/json',
dataType: 'text',
error:
function(result){
alert(result)
},
success:
function(result){
alert(result)
}
})
})
views.py
class ExistingStudentDashboard(TemplateView):
.../// rest of the code
def delete(self, request, pk, format=None):
post1 = Existing_student_posts.objects.filter(id = pk).first()
post2 = Future_student_posts.objects.filter(id = pk).first()
post3 = Teacher_posts.objects.filter(id = pk).first()
post4 = Employee_posts.objects.filter(id = pk).first()
if post1:
post1.delete()
elif post2:
post2.delete()
elif post3:
post3.delete()
else:
post4.delete()
get_context_data()
urls.py
path('existing-delete/,<int:pk>', views.ExistingStudentDashboard.as_view(), name = 'existing-delete'),
Getting Error in Console like bellow
Not Found: /existing-delete/61/
Browser Console Error
Browser Console Error
What I am doing wrong to delete post. Feel free to ask about more clarification. Any help will be appreciated :)
You have a typo in your path, change it to this
path('existing-delete/<int:pk>', views.ExistingStudentDashboard.as_view(), name = 'existing-delete'),
Edit:
Use this to get the csrf token in javascript
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]);
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
var csrftoken = getCookie('csrftoken');
Then while making the ajax request, pass that on the headers.
headers: {"X-CSRFToken":csrftoken }

send list value from django template to the django view

I have a code written which dynamically add a list when the user clicks on the add button.
for eg two lists are created-
<ul>
<li>samsung galaxy</li>
<li>xiaomi redmi note 5</li>
</ul>
code of frontend for adding li
<div class="compare_val"> <input type="text" id="txtVal" placeholder="write
to add">
<button onclick="addLi()" class="btn">Add</button></div>
<ul id="list">
<li>{{ Brand }}</li>
</ul>
<button id="Com_action" class="btn btn-danger ml-3"
onclick="ComAction()">Compare</button>
<script>
function addLi()
{
var txtVal = document.getElementById('txtVal').value,
listNode = document.getElementById('list'),
liNode = document.createElement("LI"),
txtNode = document.createTextNode(txtVal);
liNode.appendChild(txtNode);
listNode.appendChild(liNode);
}
</script>
now I want to send the li data as a list
['samsung galaxy', 'xiaomi redmi note 5'] to the view
when the user clicks on the compare button.
please help me to achieve this.
You will need to modify your scripts to include csrfmiddlewaretoken and send data using XmlHttpRequest (I'm assuming you are not using jquery):
<script>
// Standard django function to get csrf_token. More info:
// https://docs.djangoproject.com/en/2.2/ref/csrf/#acquiring-the-token-if-csrf-use-sessions-and-csrf-cookie-httponly-are-false
function getCookie(name) {
let cookieValue = null;
if (document.cookie && document.cookie !== '') {
var 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;
}
const listNode = document.getElementById('list');
let brands = [];
function addLi() {
let txtVal = document.getElementById('txtVal').value,
liNode = document.createElement("LI"),
txtNode = document.createTextNode(txtVal);
liNode.appendChild(txtNode);
listNode.appendChild(liNode);
// Save newly added brand to array
brands.push(txtVal);
}
function ComAction() {
// Prepare AJAX request
let xhr = new XMLHttpRequest(),
data = new FormData();
// Add token
data.append('csrfmiddlewaretoken', getCookie('csrftoken'));
// Add all brands
brands.forEach(function (brand) {
data.append('brand', brand);
});
// We are sending it via POST request to url '/'
xhr.open('POST', '/', true);
xhr.onload = function () {
if (xhr.status === 200) {
alert('Data received successfully. Brands are ' + xhr.responseText);
} else if (xhr.status !== 200) {
alert('Request failed.');
}
};
// Actually send request
xhr.send(data);
}
</script>
Your django endpoint can process brands like this:
views.py:
def index(request):
if request.method == 'POST':
brands = request.POST.getlist('brand')
return HttpResponse(", ".join(brands))
return render(request, 'index.html')
If you want django to send data and redirect user, modify script:
// ...
xhr.open('POST', '/', true);
xhr.onload = function () {
if (xhr.status === 200) {
data = JSON.parse(xhr.responseText);
alert('Data received successfully. Brands are ' + data.brands);
window.location.replace(data.redirect_url);
} else if (xhr.status !== 200) {
alert('Request failed.');
}
};
xhr.send(data);
and django:
views.py:
def index(request):
if request.method == 'POST':
brands = request.POST.getlist('brand')
response_data = {
'brands': brands,
'redirect_url': '/new_url'
}
return JsonResponse(response_data)
return render(request, 'index.html')
First get the list -
var lis = document.getElementById("selectedli").getElementsByTagName("li");
now store them to an input -
<input name="id_selected" type="text" hidden>
Now, you can't pass the array directly, Use jQuery.param(yourObject).
document.getElementById("id_selected").value = jQuery.param(lis)
The param() method creates a serialized representation of an array or an object that can be understandable by various frameworks like php, ruby, django etc.
For again converting it to python
from urllib import parse
value = parse.parse_qs(self.request.POST.get('name'))
If you want to use ajax you can. This code is not tested by me, so report if any error occurs.

My ajax post request gets 403 forbidden by django

I was trying to implement on keyup search with django and jquery following this video
but when I try the code everytime it returns forbidden 403!
the html page:
<div class="search-input">
<form>
{% csrf_token %}
<button>بحـث</button>
<input
type="text"
name="q"
id="search"
placeholder="Est: Game of thrones, Vikings or Deadpool"
/>
</form>
</div>
<div class="search-results"></div>
urls.py:
path('search/', views.search_titles, name='search')
views.py:
def search_titles(request):
if request.method == 'POST':
search_text = request.POST['search_text']
else:
search_text = ''
search_results = Media.objects.filter(
is_published=True, title__contains=search_text)[:5]
context = {
'search_results': search_results
}
return render(request, 'partials/_search_results.html', context)
the jquery file:
$("#search").on("keyup", function() {
$.ajax({
type: "POST",
url: "/search/",
data: {
search_text: $("#search").val(),
csrfmiddlewaretoken: $("input[name=csrfmiddlewaretoken]").val()
},
success: searchSuccess,
dataType: "html"
});
});
function searchSuccess(data, textStatus, jqXHR) {
$("search-results").html(data);
}
});
search_results.html ( that i don't even know the reason of )
{% if search_results.count > 0 %} {% for result in search_results %}
<li>
{{ result.title }}
</li>
{% endfor %} {% else %}
<li>Nothing to show</li>
{% endif %}
This is likely happening because you are not properly setting up AJAX to pass your CSRF token. The Django docs have a great section on how to set this up. Here's the short story.
First, you'll need to acquire the token:
Here's how to do it if CSRF_USE_SESSIONS and CSRF_COOKIE_HTTPONLY in your settings are False:
// using jQuery
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');
// using jQuery
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');
OR, Here's how to do it if CSRF_USE_SESSIONS or CSRF_COOKIE_HTTPONLY in your settings are True:
{% csrf_token %}
<script type="text/javascript">
// using jQuery
var csrftoken = jQuery("[name=csrfmiddlewaretoken]").val();
</script>
IN BOTH CASES, you'll also need to set up the token on your AJAX request:
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});

reactjs/redux + django CSRF protection

I am trying to make an AJAX request from my reactjs frontend to my django backend but I am getting this error upon POST. I'm not sure how to properly pass CSRF tokens around for my form POST to work properly
Forbidden (CSRF token missing or incorrect.): /api/contact
[05/Nov/2016 03:43:14] "POST /api/contact HTTP/1.1" 403 2502
I created a react component and added it into my form
CSRF component
import React from 'react';
import $ from 'jquery';
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 = $.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;
}
const Csrf = () => {
let csrfToken = getCookie('csrftoken');
return (
<input type="hidden" name="csrfmiddlewaretoken" value={ csrfToken } />
);
};
export default Csrf;
Contact form component:
const ContactForm = ({ formOnChange, onFormSubmit, isFullNameValid, isEmailValid, isMsgValid }) => {
let rows = 10;
let tabindex = 8;
let isSubmitDisabled = !(isFullNameValid && isEmailValid && isMsgValid);
return(
<div className="form-wrapper">
<form className="contact-form" onChange={ formOnChange }>
<Csrf />
<input className={ isFullNameValid ? "" : "active" } type="text" name="fullname" placeholder="Full Name *" />
<div className="email-phone-group">
<input type="text" name="phonenumber" placeholder="Phone Number"/>
<input className={ isEmailValid ? "" : "active" } type="text" name="email" placeholder="Email *"/>
</div>
<textarea className={ isMsgValid ? "" : "active" } rows={ rows } tabIndex={ tabindex } name="message" placeholder="Message... *"/>
<button disabled={ isSubmitDisabled } className="contact-form-submit-btn" type="button" onClick={ onFormSubmit }>Submit</button>
</form>
</div>
);
};
My redux action calls this AJAX function
export function contactSubmission(contactSubmission) {
// thunk
return dispatch => {
console.log("contact form submitted");
console.log(contactSubmission);
$.ajax({
method: 'POST',
url: '/api/contact',
dataType: 'json',
success: payload => {
if (payload.error) {
return dispatch(contactSubmissionFailure());
} else {
return dispatch(contactSubmissionSuccess(payload));
}
},
error: payload => {
console.log("ajax error");
console.log(payload);
return dispatch(contactSubmissionFailure());
}
});
};
}
you should put the following code before $.ajax to send a CSRF code:
$.ajaxSetup({
headers: {"X-CSRFToken": getCookie("csrftoken")}
});
...THEN YOUR CODE
$.ajax({...});
You can notice that you have already set getCookie.
With this should work properly.

CSRF token missing or incorrect using Jquery

I have the following code below but I still get "CSRF token missing or incorrect." error. anyone spot what I have done wrong here?
<form method="post" action="" id="registration">
{{ form.as_p }}
<input type="submit" value="{% trans 'Submit' %}" />
</form>
<script>
$('#registration').submit(function(e){
e.preventDefault(); //prevent default form submit
$.ajax({
url: '/accounts/registerAjax/',
type: 'POST',
contentType: "application/json;charset=utf-8",
dataType: "json",
data: {
'csrfmiddlewaretoken': '{{ csrf_token }}',
'id_username': $("#id_username").val(),
'id_email': $("#id_email").val()
},
success: function() {
alert('Test');
},
error: function(errorThrown){
console.log(errorThrown);
alert('Error');
alert(errorThrown);
}
});
From the docs.
on each XMLHttpRequest, set a custom X-CSRFToken header to the value of the CSRF token.
As a first step, you must get the CSRF token itself. The recommended source for the token is the csrftoken cookie, which will be set if you’ve enabled CSRF protection for your views as outlined above.
// using jQuery
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');
The above code could be simplified by using the jQuery cookie plugin to replace getCookie:
var csrftoken = $.cookie('csrftoken');