Converting formData to forms.Form in django - ajax

I would like to allow user to key in a quiz code and gets an alert to tell whether if the code is still invalid without refreshing the page. I already read a lot of Django AJAX and JQuery tutorials but most of them seem outdated because they do not cover the part where csrf token must be send.
In my settings.py, I set CSRF_USE_SESSIONS to True.
This is my forms.py
class codeForm(forms.Form):
code = forms.IntegerField(label='Question Code')
In my html file, I have this
<form class="card__form" id="code-form" method="POST">
{% csrf_token %} <script type="text/javascript"> // using jQuery
var csrftoken = jQuery("[name=csrfmiddlewaretoken]").val(); </script> {{form.as_p}
<center><input type="submit" class="btn btn-primary card__submit" id="submit_code"></center>
Just before the tag, I have this :
<script>
$(document).ready(function(){
$("#submit_code").click(function(){
alert("Text: ");
event.preventDefault();
var myform = document.getElementById("code-form");
var form = new FormData(this);
form.append('csrfmiddlewaretoken', csrftoken);
$.ajax({
data : form,
dataType:'json',
type: 'POST',
method: 'POST',
url: '{% url 'student:process_code' %}',
contentType: false,
processData: false,
success: function(context) {
alert(context.msg);
},
error: function(context) {
alert(context.msg);
}
});
});
});
</script>
In my views.py
def process_code(request):
context = {}
if request.method == 'POST':
form = codeForm(request.POST)
if form.is_valid():
cd = form.cleaned_data
code = cd.get('code')
print('yay')
if code.isdigit():
The unexpected result was the form is not valid (form.is_valid() = false). Thus, I think my formData object is not converted to a valid forms.Form type.
I also tried to use form = codeForm(request.POST['code']) but it return more error.
How can I get around this? I prefer not to use serialize() because I read that it cannot be used for uploading files which will be my next feature to work on after this has settled. I wanted to use forms.Form because it has cleaned_data method. If you could provide a good solution although not using forms.Form but with good reasoning, I will appreciate it. Thank you so much

try FormData(myform), not "this"

Related

How to make a ajax request using post method

I made an ajax request using post method in django..its wokring perfectly..the problem is its calling the complete html page rahter than a div..i want to call only a div..i tried but unable to find the exact solution..
<script>
$(document).ready(function(){
$('#Category').change(function(event){
event.preventDefault();
var e = document.getElementById("Category");
var value = e.options[e.selectedIndex].value;
$.ajax({
url: "/charts/",
type: "post",
dataType: "html",
data: value,
success: function(data) {
$('#div1').html(data);
}});
return false;
});
});
</script>
I want only div content with id #div1..i already tried find and replace method
What is the nature of the event ? Is it a button ? an Input ?
If it is an input as <input type="submit">, the default action is to reload the page like a form.
Did you check if your div id is really div1?
$("#div1").append("your html code"+data+" your html code")

Django form submitted with ajax redirects to form action instead of calling success

I have simple form
class TimeForm(forms.Form):
time = forms.TimeField()
date = forms.DateField()
def clean_date(self):
time = self.cleaned_data['time']
date = self.cleaned_data['date']
date_time = datetime.combine(date, time)
if datetime.now() > date_time:
raise ValidationError("datetime error")
return start_date
with class based view
class TimeView(View):
#staticmethod
def post(request):
form = TimeForm(request.POST)
if form.is_valid():
# do something
json_data = json.dumps({'some_record': value})
else:
json_data = json.dumps({'errors': form.errors})
return HttpResponse(json_data, content_type='application/json')
In html I have standard form with submit connected do ajax
<form action="/time_url/" method="POST" id="time_form">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit">
</form>
<script>
$('#time_form').submit(function(event) {
event.preventDefault();
$.ajax({
type: "POST",
url: '/time_url/',
dataType: 'json',
data: $(this).serialize(),
success: function(data, textStatus, jqXHR){
alert('yay');
}
})
});
</script>
and I'd like to be able to submit this form without page reload. Everything seems to work perfectly but success function of ajax is not triggered, instead page is redirected to /time_url/ with json data. It doesn't matter wheter form is valid nor not, it's always redirected.
I've tried also with
return JsonResponse(form.errors.get_json_data())
instead of
return HttpResponse(json_data, ...)
as suggested here Django form submit with ajax but without success.
I'm new to javascript but for me it looks like problem with ajax, since proper data is served by server.
Thanks for any tips.

Flask - Validate several forms on Ajax request

I'm trying to validate four forms from an Ajax request. My problem is that only one form is validated (geometry_building_form). The others do not contain errors, only an empty dictionary.
Another problem I have is that the validate_on_submit method does not work, I have to use the validate method.
This is the Flask view.
#app.route('/', methods=['GET', 'POST'])
#app.route('/index', methods=['GET', 'POST'])
def building():
building_parameters_form = BuildingParametersForm()
building_geometry_form = BuildingGeometryForm()
wind_form = WindForm()
topography_form = TopographyForm()
if request.method == 'POST':
if building_geometry_form.validate() and building_parameters_form.validate() and wind_form.validate() and topography_form.validate():
return redirect('/index')
else:
return jsonify(data=wind_form.errors) #Testing the wind form
return render_template('wind/building.html', bp_form=building_parameters_form,
bg_form=building_geometry_form, w_form=wind_form, t_form=topography_form)
This is the Ajax code.
<script>$(document).ready(function() {
$("#button").click(function(event) {
var csrf_token = "{{ csrf_token() }}";
var url = "{{ url_for('building') }}";
event.preventDefault();
$.ajax({
type: "POST",
url: url,
dataType: 'json',
data: $('#geometry-form, #parameters-form, #wind-form, #topography-form').serialize(),
success: function (data) {
console.log(data)
}
});
$.ajaxSetup({
beforeSend: function(xhr, settings) {
if (!/^(GET|HEAD|OPTIONS|TRACE)$/i.test(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrf_token)
}
}
})
});
});
</script>
FormFields are useful for editing child objects or enclosing multiple related forms on a page which are submitted and validated together. While subclassing forms captures most desired behaviours, sometimes for reusability or purpose of combining with FieldList, FormField makes sense. (Taken from Documentation)
With that in mind-- you may want to create a wrapping form that encloses your sub-forms:
from wtforms import FormField
class BuildingForm(Form):
building = FormField(BuildingGeometryForm)
wind = FormField(WindForm)
topography = FormField(TopographyForm)
The later when you're processing the request, form = BuildingForm() will allow you to do form.validate_on_sumbit() and it will validate and enclose the various subforms as expected.

Phoenix - invald CSRF on AJAX post

I'm learning to use the Phoenix framework, and I'm trying to do an AJAX post to a controller action - however, I'm running into a problem with the CSRF protection.
For starters, I'm not using a form - just want to pass text from an input to the controller:
<input type="text" id="raw-input" />
<button id="send-button">Send it!</button>
<script>
$("#send-button").click(function(){
var input = $("#raw-input").val();
$.ajax({
url: "/test/process",
type: "POST",
dataType: "json",
beforeSend: function(xhr) {xhr.setRequestHeader("X-CSRF-Token", $("meta[name='csrf-token']").attr("content"))},
data: {"input" : input},
success: function(response){
console.log(response);
}
});
});
</script>
The controller (not worried about doing anything input yet... just want to verify a successful post!):
def process(conn, %{"input" => input}) do
IO.puts "got it!"
end
And the router:
post "/test/process", TestController, :process
I pretty much lifted the $.ajax call from a Rails app where it was working fine, but it's not doing the trick here - running this returns a 403 error and logs (Plug.CSRFProtection.InvalidCSRFTokenError) invalid CSRF (Cross Site Request Forgery) token, make sure all requests include a valid '_csrf_token' param or 'x-csrf-token' header.
Can anyone offer any guidance? Thank you!
This is because Phoenix does not create a meta tag with the CSRF token by default. They're only included in forms generated by Phoenix's helper functions, and they're in a hidden input.
To get a CSRF token programatically in Phoenix, you can call Plug.CSRFProtection.get_csrf_token/0. There are many ways to pass this to your JS. You can add a meta tag to your layout to include it in every page but that might not be very efficient since it'll be generated for all pages. You can also just store it in a JS variable in the views that you require them in:
<input type="text" id="raw-input" />
<button id="send-button">Send it!</button>
<script>
$("#send-button").click(function(){
var CSRF_TOKEN = <%= raw Poison.encode!(Plug.CSRFProtection.get_csrf_token()) %>;
var input = $("#raw-input").val();
$.ajax({
url: "/test/process",
type: "POST",
dataType: "json",
beforeSend: function(xhr) {
xhr.setRequestHeader("X-CSRF-Token", CSRF_TOKEN);
},
data: {"input" : input},
success: function(response){
console.log(response);
}
});
});
</script>
Phoenix already has helper csrf_meta_tag. Include it in the layout like so:
<html lang="en">
<head>
<%= csrf_meta_tag %>
...
And then use it in your js like so: $("meta[name='csrf-token']").attr("content")
If you want to skip the CSRF token check (in case you are developing APIs only) then you can comment out below line -
plug :protect_from_forgery
inside your respective _web/router.ex

Django-ajax: CSRF verification failed. Request aborted

I am working with django server side form to save details in DB.
<form id="form_save_file" enctype="multipart/form-data">
{% csrf_token %}
<label class="control-label col-md-4">File:</label>
<div class="col-md-8">
{{form.fa_file}}
</div>
<label class="control-label col-md-4">Name:</label>
<div class="col-md-8">
{{form.name}}
</div>
</form>
I am using ajax to post request.
$("#form_save_file").submit(function(e) {
$.ajax({
type: "POST",
url: '/url/',
data: $("#form_save_file").serialize(),
contentType: false,
processData: false,
success: function(data){}
});
I have included middleware classes in settings.py
MIDDLEWARE_CLASSES = (
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'request.middleware.RequestMiddleware'
)
When I removed contentType and processData in ajax request, request.FILES is empty in views.py and otherthings are working fine.
contentType option to false is used for multipart/form-data forms that
pass files.
When one sets the contentType option to false, it forces jQuery not to
add a Content-Type header, otherwise, the boundary string will be
missing from it. Also, when submitting files via multi-part/form one
must leave the processData flag set to false, otherwise, jQuery will
try to convert your FormData into a string, which will fail.
To try and fix your issue:
You are using jQuery's .serialize() method which creates a text string
in standard URL-encoded notation.
You need to pass un-encoded data when using "contentType: false".
Try using "new FormData" instead of .serialize():
Source: https://stackoverflow.com/a/20863123/3345051
Revised Code:
$("#form_save_file").submit(function(e) {
e.preventDefault();
var $this = $(this);
var postURL = '/url/';
var formData = new FormData(this);
$.ajax({
type: "POST",
url: postURL,
data: formData,
mimeType: "multipart/form-data",
contentType: false,
cache: false,
processData: false
})
.done(function(response) {
// Do something if POST is successful
})
.fail(function() {
// Do something if POST is unsuccessful
})
})
disabled csrf on particular view with #csrf_exempt decorator and build custom security with a random number/string

Resources