I am learning Django2,and try to make a login page with csrf_token and ajax.
I hope that if user hasn't lgoin,that will turn to the login page and send a variable next as a tag of the page before login.If user login successfully that I can turn to the homepage or page marked by next.
I read the docs of Django2, and try to code like below,however,when I click "LOGIN" button,it just refresh the login page and get no error
I am confused and have no idea already.Please help.
login views:
def login(request):
if request.is_ajax():
uf = UserForm(request.POST)
if uf.is_valid():
# get info from form
username = uf.cleaned_data['username']
password = uf.cleaned_data['password']
user = auth.authenticate(request, username=username, password=password)
if user is not None: # user match
auth.login(request, user)
if request.GET.get('next'):
next_url = request.GET.get('next')
return JsonResponse({'redirect_url': next_url})
# return redirect(request.GET.get('next'))
else:
return JsonResponse({'redirect_url': 'home'})
else: # user not match
error_msg = ["username or pwd mistake"]
return JsonResponse({'error_msg': error_msg})
else:
uf = UserForm()
return render(request, 'login.html', {'uf': uf})
html :
<form>
{% csrf_token %}
{{ uf.username }}
{{ uf.password }}
<div id="errorMsg"></div>
<button type="submit" class="btn btn-default" id="loginButton">login</button>
<input type="hidden" name="next" id="redirect-next" value="{{ next|escape }}"/>
</form>
JQuery:
$("#loginButton").click(function () {
$.ajax({
url: "",
type: 'POST',
dataType: "json",
data: {username: $("#inputEmail3").val(), password: $("#inputPassword3").val()},
beforeSend: function (xhr, settings) {
var csrftoken = Cookies.get('csrftoken');
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
},
success: function (result) {
if (result.error_msg) {
$('#errorMsg').show().text('user info error') //print an alert on the page
}
else {
location.href = result.redirect_url //turn to homepage or page before login
}
}
})
});
You don't need to take effort to write a login view of your own like this. Django provides easier methods to implement it.
First make sure the following are included in your settings.py
MIDDLEWARE_CLASSES = [
...
'django.contrib.auth.middleware.AuthenticationMiddleware',
...
]
INSTALLED_APPS = [
...
'django.contrib.auth',
'django.contrib.contenttypes',
...
]
Add all the login URLs to your main urls.py:
from django.urls import path
from django.conf.urls import include
urlpatterns = [
....
path('accounts/', include('django.contrib.auth.urls')),
....
]
Don't forget to run python manage.py migrate to create the tables required for the auth app. Now that the app and URLs are ready, templates need to be created. All the templates for the app should be placed under a folder named registration under your templates directory. The directory structure should be something like.
your_django_app/
templates/
registration/
login.html
__init__.py
apps.py
settings.py
urls.py
views.py
wsgi.py
The contents of the login.html should be something like:
<form id="loginform" action="{% url 'login' %}" method="POST">
{% csrf_token %}
{% if next %}
<input type="hidden" name="next" value="{{ next }}" />
{% endif %}
<input name="username" id="id_username" type="text">
<label>Username</label>
<input name="password" id="id_password" type="password">
<label>Password</label>
{% if form.errors %}
Error! Wrong credentials.
{% endif %}
<button type="submit">Login</button>
</form>
After this include these in your settings.py file for redirecting users correctly after login.
LOGIN_REDIRECT_URL = '/'
LOGIN_URL = '/accounts/login'
You are all set to go. Make sure to create at least one user before trying this out by running python manage.py createsuperuser. For all pages that require users to login before viewing them you can use the #login_required decorator above their respective view functions to redirect them to the login page before showing the page. Example:
from django.shortcuts import render
from django.contrib.auth.decorators import login_required
#login_required
def home(request):
return render(request, 'home/index.html')
Here there is a short and simple way to parse the csrf_token using ajax:
Inside the script tag.
$.ajax({
url: window.location.pathname,
type: 'POST',
data: {
......,
// Note this step.
'csrfmiddlewaretoken': "{{ csrf_token }}"
},
success: function() {
.....
}
});
Hope things work well as I have used this thing to parse the csrf_token in my 2 Django based projects. Cheers!
This might be related to this issue
As your button tries to submit the form but you want it to be handled handled by the script.
try changing the button type to
type="button"
Related
I'm trying to POST form in Django using Ajax. I've already done this way before but now i cant find whats wrong with my code. When submitting the form, ajax POST's to wrong URL even though i've provided the right URL. I want to post to "/upload/videoUpload/" but it keeps on posting to "/upload".Below is the code.
HTML:
<form id="videouploadForm" method="POST" >
{% csrf_token %}
<input type="text" id="vidlc" name="video" value="submit" style="display: none" >
<input type="submit" id="sBm120" style="display: none"/>
</form>
AJAX:
<script>
$('#sBm120').trigger('click');
$(document).ready(function() {
$("#videouploadForm").submit(function(event){
event.preventDefault();
$.ajax({
method:"POST",
url:"/upload/videoUpload/",
data: {
'video': $('#vidlc').val(),
'csrfmiddlewaretoken': $('input[name=csrfmiddlewaretoken]').val()
},
success: function(data){
if (data.status){
alert(data.status);
var result = " <video poster='{% static 'images/single-video.png' %}' style='height:30vh' controls='controls' width='100%' height='30%'><source src='http://gateway.ipfs.io/ipfs/"+data.filehash+"' type='video/mp4; codecs='avc1.42E01E, mp4a.40.2'></video>";
document.getElementById("upv").innerHTML=result;
}
}
});
return false; //<---- move it here
});
});
</script>
URLS.py:
path('upload/videoUpload/', uploadVid, name="uploadVideo"),
have you tried to use Django url template tags?
url:"/upload/videoUpload/", to
url:" '{% url " uploadVideo" %} ",
Hope it works!
Sorry if you dont see properly, writing from my phone :)
Please note, I'm using the Laravel framework.
Also please note, there are similar questions on SO, I've checked them, but wasn't able to solve my problem based on those solutions...
Even though I set my CSRF token right to my knowledge, I'm not sure why it won't work.
When checking the console, it seems I have 3 cookies: two Request cookies of which one is called XSRF-TOKEN and one is called laravel_session. And one respone laravel_session cookie. All have a different value!!!
My Vue:
new Vue({
el:'body',
http: {
root: '/root',
headers: {
'X-CSRF-Token': $('meta[name=_token]').attr('content')
}
},
});
My head:
<meta name="_token" content="{!! csrf_token() !!}"/>
My Vue component addNew method:
Vue.component('things',{
template:'#things-panel-template',
data(){
return {
list: [],
newThing: {
body: '',
// _token: $('meta[name=_token]').attr('content'),
// tried removing token from head meta and adding up here.
},
}
},
methods:{
addNew(){
var thing = this.newThing; // get input
this.newThing = {body:''}; // clear input
this.$http.post('/api/things/add',thing) // send
},
},
});
My route:
Route::post('/api/things/add',function(){
return App\Thing::create(Request::get());
});
And finally, the form in my Vue Template:
<form action="/things/add"
method="POST"
#submit.prevent="addNew"
>
<div class="form-group">
{{ csrf_field() }}
<label for="">Add</label>
<input type="text"
name="body"
id="task-body"
class="form-control"
v-model="newThing.body"
>
<button :disabled="!isValid"
class="btn btn-primary"
type="submit"
>Add</button>
</div>
</form>
Try this:
this.$parent.$http.post('/api/things/add', thing)
instead of
this.$http.post('/api/things/add', thing)
Or set default values using the global configuration:
Vue.http.headers.common['X-CSRF-TOKEN'] = $('meta[name=_token]').attr('content');
I found the answer myself:
If you're gonna work with a vue-component, you should just add the token to that component instead. Otherwise it won't go with your ajax request.
So put this part underneath the template in the component:
http: {
root: '/root',
headers: {
'X-CSRF-Token': $('meta[name=_token]').attr('content')
}
},
Do this to check if your token was properly sent inside the headers:
Go to google chrome, open dev-tools, go to the network tab and Reload.
Make the ajax call and look at the file added in the network tab, open it and go to the 'Headers' tab.
Look at the bottom where it says: 'Request Headers' and check if the token was properly added in the request.
I have seen answers (here and here) for similar questions, but none of them work in my case. I have a simple form in a template, I am using bootstrap for rendering.
Once I submit the form, the response is rendered directly in the browser. When I return to the previous page (with the browser's button) then the success part of the AJAX call is executed.
forms.py
class QueryForm(forms.Form):
query = forms.CharField(label='Discover something', max_length=256)
views.py
def query_view(request, id):
if request.method == 'POST':
# Just for testing, send True
response_data = {
'result': True
}
return HttpResponse(json.dumps(response_data), content_type="application/json")
else:
try:
# Create a form and send it to the template
query_form = QueryForm()
return render(request, 'query_template.html', {'query_form': query_form})
except ObjectDoesNotExist:
return render(request, 'error.html')
urls.py
urlpatterns = [
url(r'^query', views.query_view, name='query_view'),
url(r'^', views.home, name='home'),
]
query_template.html
{% extends 'base.html' %}
{% load static %}
{% load bootstrap3 %}
{% block content %}
{# Display a form #}
<form method="post" class="form">
{% csrf_token %}
{% bootstrap_form query_form %}
{% buttons %}
<button class="btn btn-primary" id="query-button">
{% bootstrap_icon "star" %} Submit
</button>
{% endbuttons %}
</form>
<ul id="result"></ul>
<script src="{% static 'scripts/main.js' %}"></script>
{% endblock %}
main.js
$('#query-button').click(function (event) {
$.ajax({
url: "/query/",
type: "POST",
data: {},
cache: false,
// handle a successful response
success: function (json) {
console.log(json); // log the returned json to the console
$("#result").html("<li>" + json.result + "</li>");
console.log("success"); // another sanity check
},
// handle a non-successful response
error: function (xhr, errmsg, err) {
console.log(xhr.status + ": " + xhr.responseText);
}
});
});
// It also includes functions to manage the CRFS token
I have been playing with the code. If instead a form I use <input> and <button id='query-button'> it renders the response without reloading the page.
You need to prevent the default submit action of the HTML form, via event.preventDefault().
You can using FormData instead of custom send data, open below links:
How to send FormData objects with Ajax-requests in jQuery?
https://developer.mozilla.org/en-US/docs/Web/API/FormData
I want to create dropdown list in django forms.
One way is to get the options and pass it to the template from views.py
Other way is via forms.py but i'm not sure how to do that.Although the code to do that is available,it's not usable for me as i want to generate options depending on the user that it logged in(that means using request parameter).Can you suggest how to do that?
The first method of passing via views.py works to the extent of generating a dropdown but i'm not able to get the value of selected option from request.It gives a null value.
Here's my code:
Template
<script type="text/javascript">
$(document).ready(function() {
$('#remove_form').submit(function() { // catch the form's submit event
$.ajax({ // create an AJAX call...
data: $(this).serialize(), // get the form data
type: $(this).attr('method'), // GET or POST
url: '/remove/', // the file to call
success: function(response) { // on success..
$('#test').html("<p style='color:green;margin-left:40%;margin-right:40%;'>Submitted!</p>"); // update the DIV
},
error: function(e, x, r) { // on error..
$('#err').html(e); // update the DIV
}
});
return false;
});
});
</script>
......
......
<form method="POST" id="remove_form" action="">{% csrf_token %}
<select id="remove">
{% for i,p in dropdown %}
<option value="{{i}}">{{p}}</option>
{% endfor %}
</select>
{{remove|crispy}}
<input class="btn btn-primary" type="submit" value="Remove">
</form>
Also note that i'm rendering this form from one view but the data goes into another view for processing via ajax call.
<select id="remove">
The select tag takes a name attribute.
<select name="remove" id="remove">
Then your form works. http://codepen.io/C14L/pen/dMKqPE
I am absolutely new to django framework and new to web development and python. Currently I'm trying to implement ajax in my project. I am not able to find any working sample. I need help with putting ajax or jquery in a django1.3 project.
Now I'm trying to implement ajax using dojango' app. I install it successfully and trying this tutorial.
urls.py:
(r'^dojango/', include('dojango.urls')),
(r'^simple/', 'views.simple'),
(r'^simple-ajax-set/', 'views.simple_ajax_set'),
views.py:
from django.shortcuts import render_to_response
from dojango.decorators import json_response
#expect_post_request
#json_response
def simple_ajax_set(request):
ret = {}
firstname = request.POST['firstname']
surname = request.POST['surname']
if len(surname)<3:
ret['error'] = 'Surname is too short.'
ret['success'] = False
if ret['success']:
# Store the data here
pass
return ret
simple.html
{% extends "dojango/base.html" %}
{% block dojango_page_title %}Simple AJAX with dojango{% endblock %}
{% block dojango_header_extra %}
<script type="text/javascript">
function userFormSubmit(){
var form = dojo.byId("userForm");
dojo.xhrPost({url:form.action,
handleAs:"json",
content:{surname:form.surname.value,
firstname:form.firstname.value
},
load:function(response, ioArgs){
if (response.success){
dojo.byId("info").innerHTML = "Submitted successfully";
} else {
dojo.byId("info").innerHTML = "Error: "+response.error;
}
},
error:function(data){ // This happens on a 500 error or alikes.
dojo.byId("info").innerHTML = "Error sending data.";
}
});
}
</script>
{% endblock %}
{% block dojango_content %}
<form id="userForm" onsubmit="userFormSubmit(); return false;" action="/simple-ajax-set/">
First name: <input id="firstname" /><br />
Surname: <input id="surname" /><br />
<input type="submit" value="Submit" /> <span id="info"></span>
</form>
{% endblock %}
When I run I got the exception
NameError at /simple-ajax-set/
name 'expect_post_request' is not defined
So I change my code as in the first part of the above tutorial, and I got the following exception
'MultiValueDictKeyError at /simple-ajax-set/' , "Key 'firstname' not found in <QueryDict: {}>" when click on the submit button at simple.html.
Please help me to find out the problem sand also share some links or codes containg ajax/jquery which works with django1.3. and python 2.7,
Can any one suggest working a hello world ajax or jquery example for django1.3?
"Pure" jQuery and django here. That made me happy when i was on your place. Good luck!