CSRF Token missing or invalid. -> First form fails other CSRF Token work - ajax

So I have a site with multiple buttons. These buttons are inside forms and use this { CSRF }. However the first button won't work.
This is a snippet of how the HTML looks like.
<form method="post" id="post-form">
{% csrf_token %}
<button type="submit" name="startVm" class="btn btn-default btn-block d-none d-md-block">StartVM</button>
</form>
<form method="post" id="post-form">
{% csrf_token %}
<button type="submit" name="stopVm" class="btn btn-default btn-block d-none d-md-block">StopVM</button>
</form>
And this is the Ajax function that I use.
$('#post-form').on('submit', function(e){
e.preventDefault();
console.log("form submitted!") // sanity check
post();
});
// AJAX for posting
function post() {
console.log("create post is working!") // sanity check
$.ajax({
url : '', // the endpoint
type : 'post', // http method
data : {},
csrfmiddlewaretoken: '{{ csrf_token }}',
contentType: 'application/x-www-form-urlencoded',
processData: true,
// handle a successful response
success : function() {
alert("Thank you for your comment!");
console.log("success"); // another sanity check
},
// handle a non-successful response
error : function(xhr,errmsg,err) {
$('#results').html("<div class='alert-box alert radius' data-alert>Oops! We have encountered an error: "+errmsg+
" <a href='#' class='close'>×</a></div>"); // add the error to the dom
console.log(xhr.status + ": " + xhr.responseText); // provide a bit more info about the error to the console
}
});
};
So as I said. The button StartVM won't work and it returns a 403 error.(Forbidden (CSRF token missing or incorrect.): /)
The second one however works without a problem.
This is the code in the view.py
def post (self, request):
if request.method == 'POST' and 'startVm' in request.POST:
print("startVM button")
return HttpResponse("{}",
content_type='application/json', status=204)
if request.method == 'POST' and 'stopVm' in request.POST:
print("stopVM button");
return HttpResponse("{}",
content_type='application/json', status=204)
return HttpResponse("{}",
content_type='application/json')
I am returning status 204 because e.preventDefault() won't work and it refreshes the whole site if I click on a button.

Firstly, ids should be unique, but you have id="post-form" on two separate forms.
You could do class="post-form" instead, and change your JS to use .post-form.
Or, for the template in your question, you could have a single <form> tag that contains both buttons.
Next, you need to include the CSRF token inside the form data.
data : {'csrfmiddlewaretoken': '{{ csrf_token }}'},
Alternatively, you could follow the suggestion in the docs, and add an X-CSRFToken header for ajax requests, then you don't need to include the token in the post data.

Related

how to request django post method values using ajax

I would like to implement simple django login method using ajax. when i want to retreive html input values using ajax in views, the request.post values are returning None. for ex print(request.POST.get('username')), it returns None.
my html form
<form action="" method="POST">{% csrf_token %}
<input type="text" name="username1" class="form-control rounded-1" id="id_username1" value="">
<input type="password" name="password1" class="form-control rounded-1" id="id_password1" value="">
</div>
<input type="button" id="btnlogin" value='Valider'>
</form>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.2/jquery.min.js"></script>
<script>
var token = '{{csrf_token}}';
//login
$('#btnlogin').click(function(){
//alert("/login");
$.ajax({
url: "{% url 'login' %}",
headers:{'X-CSRFToken':token},
method:"POST",
data:{},
dataType: 'json',
success: function (data) {
if (data.status){
console.log('Success');
}
else{
console.log("login failed");
}
}
});
})
</script>
urls.py
path('login/', views.login_page, name='login'),
views.py
def login_page(request):
if request.method == 'POST':
username = request.POST.get('username1')
password = request.POST.get('password1')
print('password :',password)
#result "password : None"
user = authenticate(username=username, password=password)
if user is not None:
login(request, user)
return JsonResponse({'status':True})
else:
return JsonResponse({'status':False})
context = {}
return render(request, 'core/login.html', context)
I do not know where is the error and how to fix this issue.
Thanx in advance.
i tried request.POST['password1']#result None
i changed to GET method. same issue.
I would like to collect forms input values in django view method using ajax

Django: Uploading files with AJAX: Form says that the file input field is empty (or CSRF token missing or incorrect)

I'm trying to add a very simple file upload modal form in my Django app.
But, when I click the submit button, the form shows me an error message: "this field is required".
Everything renders correctly:
My main page loads correctly
When I click in the "Agregar archivo adjunto" button ("add attachment"), the modal form shows correctly, and all the fields are rendered as I want them to.
The issue comes when I click on the "Adjuntar archivo" ("attach file") button in my modal field: The form throws an error, as if I was trying to upload a "null" file!
Now... I forgot to add cache: false, contentType: false, processData: false to the $.ajax() call, but, when I add them, I get the following error: Forbidden (CSRF token missing or incorrect.). So... I don't know how to proceed!
I've already wrote (successfully) a modal form which helps me add notes (related) to my lead object (using this reference), and I'm trying to reproduce exactly the same process for a file upload modal dialog... but it doesn't work :(
Any help will be really appreciated.
By the way: I'm testing this using Chrome (no IE will be used!)
Here is my code:
models.py
def lead_dir_path(instance, filename):
"""
Files will be saved to: MEDIA_ROOT/leads/<int:pk>/<filename>
where <int:pk> is lead's primary key, and <filename> is just that.
Filename will be set to an UUID value.
"""
ext = filename.split('.')[-1]
filename = '%s.%s' % (uuid.uuid4(), ext)
return 'leads/%s/%s' % (instance.lead.pk, filename)
class ArchivosAdjuntosLead(models.Model):
lead = models.ForeignKey(Lead, on_delete=models.CASCADE)
descripcion = models.CharField(max_length=100)
archivo = models.FileField(upload_to=lead_dir_path)
views.py
def agregar_adjunto_json(request, pk):
"""
Adds a file to lead with id=pk
"""
context = {}
data = {}
lead = get_object_or_404(Lead, pk=pk)
context['lead'] = lead
if request.method == 'POST':
form = AdjuntarArchivoLeadForm_v2(request.POST, request.FILES)
if form.is_valid():
form.save();
data['form_is_valid'] = True
else:
data['form_is_valid'] = False
else:
form = AdjuntarArchivoLeadForm_v2()
form.initial = {'lead': lead}
context['form'] = form
data['html_form'] = render_to_string(
template_folder + 'partial_templates/partial_adjuntar_archivo.html',
context,
request = request,
)
return JsonResponse(data)
forms.py
class AdjuntarArchivoLeadForm_v2(forms.ModelForm):
class Meta():
model = ArchivosAdjuntosLead
fields = ['lead', 'descripcion', 'archivo']
widgets = {
'lead': forms.TextInput(attrs={'class':'form-control', 'style':'display:none;'}),
'descripcion': forms.TextInput(attrs={'class':'form-control'}),
'archivo': forms.FileInput(attrs={'class':'form-control'}),
}
partial_adjuntar_archivo.html
I use this partial template to create a modal form:
<form method="POST" enctype="multipart/form-data"
action="{% url 'leads:agregar_adjunto_v2' pk=lead.pk %}"
id="js_adjuntar_archivo_form">
{% csrf_token %}
<div class="modal-header">
<h4 class="modal-title">Adjuntar archivo</h4>
</div>
<div class="modal-body">
{{ form.as_p }}
<div class="modal-footer">
<button type="submit" class="btn btn-primary col-4">Adjuntar archivo</button>
<button type="button" class="btn btn-secondary col-4" data-dismiss="modal">Cancelar</button>
</div>
</div>
</form>
my_lead_page.html
This is the page where I create the modal form:
{% extends "leads/base.html" %}
{% load static %}
{% block contenido %}
<!-- Lots and lots of info -->
<button type="button" class="btn btn-sm btn-primary col-2" id="btn_agregar_adjunto">
Agregar archivo adjunto
</button>
{% endblock %}
{% block other_scripts %}
<script type="text/javascript" src="{% static 'js/leads/archivos_adjuntos.js'%}"></script>
{% endblock %}
archivos_adjuntos.js
$(function() {
$("#btn_agregar_adjunto").click(function() {
$.ajax({
url: 'adjuntar_archivo/',
type: 'get',
dataType: 'json',
beforeSend: function() {
$("#modal-form").modal("show");
},
success: function(data) {
$("#modal-form .modal-content").html(data.html_form);
}
});
});
$("#modal-form").on("submit", "#js_adjuntar_archivo_form", function() {
var form = $(this);
$.ajax({
url: form.attr("action"),
data: form.serialize(),
type: form.attr("method"),
dataType: 'json',
cache: false,
contentType: false,
processData: false,
success: function(data) {
if(data.form_is_valid) {
alert("Archivo adjuntado");
} else {
$("#modal-form .modal-content").html(data.html_form);
}
}
});
return false;
});
});
Instead of form.serialize() try sending it with js formData() it should work.
Here is an example:
$("#modal-form").on("submit", "#js_adjuntar_archivo_form", function() {
$that = this;
var form = new FormData($(this)[0]);
$.ajax({
url:$that.attr("action"),
type:$that.attr("method"),
data:form,
processData: false,
contentType: false,
// rest of the code'''
});
return false;
});

how template POST parameter to view?

Hi~ o( ̄▽ ̄)ブ ,I have a question about django template POST value to view.I have done this:
buttons:
for item in items
<input type="button" id="btn1" class="btn btn-info btn-xs" name="{{item.sn}}" value="parse" onclick="func1(this.name)"
<input type="button" id="btn2" class="btn btn-info btn-xs" name="{{item.name}}" value="report" onclick="func2(this.name)
A button passes a unique value to a view's function.
views:
if request.method == 'POST':
if btn1...?
function1...
if btn2...?
function2...
and now I want to get the corresponding parameter when i click a button. and they are used separately for two functions. I used ajax to post parameters.but I don't know how to make btn1's parameters for function1, and btn2's parameters for function2. As the '?' mark indicates.How to write the ajax code andthe view's '?' code
please and thanks!
Probably you need some like this
jQuery
function func1(param){
$.ajax({
dataType: "json",
url: '/your/url/here/',
data: {"button": "button1",
"param": param,
"csrfmiddlewaretoken": $("input[name=csrfmiddlewaretoken]").val()
},
type: "POST",
success: function(data){
console.log("Post OK");
}
});
}
python
if request.is_ajax():
button_name = request.POST.get('button', None)
button_param = request.POST.get('param', None)
if button_name == "button1":
func_form_button1(param)
elif button_name == "button2":
func_form_button2(param)

Doesn't send the $scope to the html

I started to work in Angular few days ago, and I have a problem that I don't know how to fix.
My website is calling a controller.js and this controller calls to an ajax function. The ajax function sent back a correct response, but I can't see it in the web. Here is the code:
var myApp = angular.module('myapp',[]);
myApp.controller('ResolveProduct', ['$scope', function($scope) {
productInformation = function($scope) {
var something;
$.ajax({
type: "GET",
dataType : "json",
async : true,
url : "/ajax/reference/200-B2",
success : function(data) {
something = data.david;
alert(JSON.stringify(something));
$scope.helper = JSON.stringify(something);
},
complete : function($scope) {
$scope.helper = JSON.stringify(something);
alert($scope.helper);
}
});
};
}]);
This sent me a correct answer, but when I do this in the HTML I don't see the answer. (Even if the alert has all the info)
<div ng-controller="ResolveProduct">
<input ng-model="info"></input> information is: {{ $scope.helper }}
<input type="button" id="commitAction" class="slim-button" value="Resolve" onclick="productInformation('')"/>
</div>
You don't need to call $scope in the html side, so change {{$scope.helper}} to {{helper}}
<div ng-controller="ResolveProduct">
<input ng-model="info"></input> information is: {{ helper }}
<input type="button" id="commitAction" class="slim-button" value="Resolve" onclick="productInformation('')"/>
</div>
Update
You have passed empty values to the $scope from the onclick="productInformation('')" method. So the $scope values are cleared .
Please copy and past my code instead of your code.
Js code
var myApp = angular.module('myapp',[]);
myApp.controller('ResolveProduct', ['$scope', function($scope) {
$scope.productInformation = function()
{
var something;
$.ajax({
type: "GET",
dataType : "json",
async : true,
url : "/ajax/reference/200-B2",
success : function(data){
something = data.david;
alert(JSON.stringify(something));
$scope.helper = JSON.stringify(something);
},
complete : function($scope){
$scope.helper = JSON.stringify(something);
alert($scope.helper);
}
});
};
}]);
Html Code
<div ng-controller="ResolveProduct">
<input ng-model="info"></input> information is: {{ helper }}
<input type="button" id="commitAction" class="slim-button" value="Resolve" **ng-click="productInformation()"**/>
</div>
Also, I have changed onclick to ng-click in your button and assigned the function with $scope in your js side ( see the change productInformation to $scope.productInformation)
You should use {{ helper }} instead of {{ $scope.helper }}.
Also, after $scope.helper = JSON.stringify(something); you should add $scope.$apply().
You need to call $scope.$apply() because you are assigning a value to $scope.helper outside the digest loop (because you are using $.ajax from jQuery).
An explanation for the digest loop in angular can be found here: How do I use $scope.$watch and $scope.$apply in AngularJS?
Please check whether it works
<div ng-controller="ResolveProduct">
<input ng-model="info"></input> information is: {{helper }}
<input type="button" id="commitAction" class="slim-button" value="Resolve" onclick="productInformation('')"/>
</div>
You can't use $scope here
Refer this for help:
http://www.bennadel.com/blog/2457-accessing-scope-on-the-dom-using-angularjs.htm

Django - Ajax modal login/registration

I have a project in which I need to pop a modal window for not authenticated users.
This modal will allow to login directly or create an account.
So it will contain two forms:
django.contrib.auth.forms.AuthenticationForm
registration.forms.RegistrationForm
Here is my view to get both forms:
def ajax_registration(request):
obj = {
'login_form': AuthenticationForm(),
'registration_form': RegistrationForm(),
}
return render(request, 'common/ajax_registration.html', obj)
And my template displaying the forms tabbed
<ul class="nav nav-tabs">
<li>{% trans 'Login' %}</li>
<li>{% trans 'Registration' %}</li>
</ul>
<div class="tab-content">
<div class="tab-pane active" id="tab1">
{{ login_form|bootstrap }}
</div>
<div class="tab-pane" id="tab2">
{{ registration_form|bootstrap }}
</div>
</div>
Question is: Since I'm using ajax to display this modal, How can I validate the selected form, preferably using the already written django-registrations register & django.contrib.auth login views ?
In addition to Maddog's answer you need some javascript to submit the form back to the URL that rendered the form. Using jquery it could be something like:
$('form').submit(function(e){
e.preventDefault();
var form = $(e.target);
$.ajax({
url: '{% url YOUR_REGISTRATION_URL %}',
type: 'post',
data: account_form.serialize() + '&' + form.serialize(),
error: function(xhr, ajaxOptions, thrownError){ alert(thrownError); },
success: function(){}
})
})
You don't need to do it with a form submit element, you could use any element with $().click(), of course.
Something like this?
def ajax_registration(request):
login_form, registration_form = False, False
if request.method == "POST":
if "email" in request.POST: # some condition to distinguish between login and registration form
login_form = AuthenticationForm(request.POST)
if login_form.is_valid():
# log in
else:
registration_form = RegistrationForm(request.POST)
if registration_form.is_valid():
# register
obj = {
'login_form': login_form if login_form else AuthenticationForm(),
'registration_form': registration_form if registration_form else RegistrationForm(),
}
return render(request, 'common/ajax_registration.html', obj)

Resources