Flask - Validate several forms on Ajax request - ajax

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.

Related

Converting formData to forms.Form in django

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"

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.

django ajax return more than one piece of html and mount

Because of a limitation in bootstrap modals that they need to be outside a postion: fixed, I need to return 2 separate pieces of html in django after an ajax response (a list of items and their modals)
Is there a way in django to return 2 pieces of redendered html?
Currently I have in the ajax view I return a single piece of html with:
return render(request, 'pages/results.html', context)
which I mount with:
$.ajax({
url: '/users/some_ajax_view/',
data: {
'filters': filters
},
success: function (data) {
$('.ajax-block').html(data)
}
})
Best solved with using the render_to_string() method and then sending multiple pieces of html via a JsonResponse to then be mounted on the front end.
eg
in your view:
modals_html = render_to_string('components/modals.html', context)
quotes_html = render_to_string('components/list.html', context )
return JsonResponse({'list': list_html,
'modals': modals_html})
then in the front end mount with:
$.ajax({
url: '/users/some_ajax_view/',
data: {
'filters': filters
},
success: function (data) {
$('#list').html(data.list)
$('#modals').html(data.modals)
}
})

How to make an ajax request to a view

I am trying to figure out how I can make an ajax request (with jquery) from my template in order to execute a view on a button click. I don't want to redirect to another page. I just need to execute the code in the view.
This is my on button click event:
$(document.body).on("click", "#download_xls",function(e) {
selected_country = ($("#button-countries").val())
selected_subareas = $('#_all_values').val();
id = "?country=" + selected_country + "&" + "regions=" + selected_subareas
whole_url = "{% url 'test_download' %}" + id
$("#download_xls").attr("href", whole_url)
});
As I pass the values in my URL, I don't even need to pass some parameters through the ajax request. I just need to execute the code in the view.
The view is something like this:
def test_download(request):
print(request.GET.get('country'))
print(request.GET.get('regions'))
fileContent = "Your name is %s"
res = HttpResponse(fileContent)
res['Content-Disposition'] = 'attachment; filename=yourname.txt'
return res
EDITED
I have added the ajax GET request in my template as:
whole_url = "{% url 'test_download' %}"+id
$.ajax({
type: "GET",
url: whole_url,
success: function(data) {
alert('sd')
},
error: function(data) {
alert('error')
},
});
I get an error cause there is no corresponding template for this view. I think I need to add something in the urls.py file.
I read here that I need to modify urls.py as:
url(r'^link-to-fun1$', views.fun1),
But its not clear to me what should be the link-to-fun1.
I tried:
url(r'^create$', 'test_download', name='test_downlad'),
But gives an error: No Reverse Match.
You could use TemplateView add to your url and use JQuery to do something, like this:
views.py
class ajax_view(TemplateView):
def get(self, request, *args, **kwargs):
id_value = request.GET['id']
value = Model.objects.filter(id=id)
data = serializers.serialize('json', value, fields=('fieldone'))
return HttpResponse(data, content_type='application/json')
urls.py
url(r'^ajax/$', ajax_view.as_view()),
JQuery
$.ajax({
data: { 'id': id },
url: '/ajax/',
type: 'get',
success: function (data) {
// Do something with the data
}
})
That's in general how you can use Ajax with Django, the important is the use of TemplateView

Ajax call failing in Django

I have the following ajax call to update a particular field of a model
$("#updateLink").click(function(){
var dec_text = $('#desc_text').val();
$.ajax({
type: "POST",
url:"/users/update_desc/",
data: {
'val': dec_text,
},
success: function(){
$(".display, .edit").toggle();
$("#descText").html(dec_text);
},
error: function(){
alert("Error");
},
});
return false;
});
and my view is this
#csrf_exempt
def update_desc(request):
if request.is_ajax():
if request.method == 'POST':
desc_text = request.POST.get('val', False)
if desc_text:
profile = user.profile
profile.desc = desc_text
profile.save()
return_message = "Sent mail"
return HttpResponse(return_message,mimetype='application/javascript')
I am constantly getting an error message and I don't know how to solve this. I even used the csrf_exempt decorator to workaround if the problem was caused by a missing csrf token but still the problem persists.
Except one ajax post which in my base template all the ajax calls are failing. Can anybody please help to understand what is happening here. I can give some more details if required.
Edit:
I have added the a js file containing this https://docs.djangoproject.com/en/dev/ref/contrib/csrf/#ajax in my base template, so it means it is present in all my templates. And I am using django 1.3 version.
Firstly, you are using POST and not sending a csrf token. Try explicitly sending the csrf token rather than using the decorator csrf_exempt.
One way of doing this is with what I have done in data. That is to fetch the csrf token (or from your own method) and pass it in your arguments.
$.ajax({
url : url,
type: "POST",
data : {csrfmiddlewaretoken: document.getElementsByName('csrfmiddlewaretoken')[0].value},
dataType : "json",
success: function( data ){
// do something
}
});

Resources