Jquery submit() not submitting form data to my view - javascript

I have the following file (app.py) that generates a Flask instance and defines a few routes and declares/initiates a simple form:
from flask import Flask, render_template, url_for
from flask_wtf import FlaskForm
import wtforms as wtf
from wtforms.fields.html5 import DecimalRangeField
app = Flask(__name__)
app.config['SECRET_KEY'] = 'youll-never-guess'
class Form(FlaskForm):
age = DecimalRangeField('age', default=30)
submit = wtf.SubmitField('submit')
#app.route('/form/', methods=['GET'])
def form():
form = Form()
return render_template('form.html', form=form)
#app.route('/form/submit/', methods=['POST'])
def submit_form():
return 'form submitted!'
def main():
app.run(debug=True, port=5000)
if __name__ == '__main__':
main()
where the templates/form.html file is as follows:
<form id="form" action="{{ url_for('submit_form') }}" method="POST" onchange="submitForm(this);">
{% for field in form %}
{{ field }}
{% endfor %}
</form>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script>
function submitForm(form) {
console.log(`submitting form ${form} ... `);
$(form).submit();
}
</script>
When I change the slider the console prints submitting form [object HTMLFormElement] ... but does not seem to call the view function submit_form. However, when I click the submit button the /form/submit/ URL is rendered with the text form submitted!. Why is this, please?

You have to rename submit field on the form because submit method/handler is shadowed by the name/id attribute.
class Form(FlaskForm):
age = DecimalRangeField('age', default=30)
sub = wtf.SubmitField('sub')
Alternatively you can add your form button directly in the template but it can't have id nor name submit.

In your code, the change method has a call back function and inside this call back function, this refers to the current call back function scope, which doesn't have any submit method.
Therefore, fetch the form object using JQuery or vanilla JS as follows:
var form = document.getElementById("form");
$(form).submit();

Related

Django smart selects doesn't work with JS cloning

I'm trying to create a page with ability to add any amount of form-copy.
I use django-smart-selects to make my form's field chained. It works fine if I have only 1 form on page.
Then I'm using javascript to make a function to clone form instance by pressing button and addind new form's ids to these clones.
The problem is when I press "+" button I get new cloned form on page, but chained-selection doesn't work anymore(only first one still works), and it seems that this clone copying all my choices from the firs form and remembering this state.
I see in terminal this response every time I choose any selection in chained fields:
[31/Oct/2022 16:42:27] "GET /chaining/filter/cash_table/LevelOne/flowtype/cash_table/CashFlowPattern/level_one/1/ HTTP/1.1" 200 115
[31/Oct/2022 16:42:29] "GET /chaining/filter/cash_table/LevelOne/flowtype/cash_table/CashFlowPattern/level_one/2/ HTTP/1.1" 200 105
But in cloned forms it doesn't happen.
My Formset is:
forms.py
from django import forms
from .models import CashFlowPattern
from django.forms import modelformset_factory
class CashFlowForm(forms.ModelForm):
class Meta:
model = CashFlowPattern
fields = '__all__'
CashFowFormSet = modelformset_factory(
CashFlowPattern,
fields=(
'flow_type',
'level_one',
'level_two',
'eom',
'amount',
'comment'
),
extra=1
)
views.py
class FormAddView(TemplateView):
template_name = 'cash_table/index.html'
def get(self, *args, **kwargs):
formset = CashFowFormSet(queryset=CashFlowPattern.objects.none())
return self.render_to_response({'formset': formset})
def post(self, *args, **kwargs):
end_of_month = (datetime.datetime.now() + relativedelta(day=31)).strftime('%Y-%m-%d')
formset = CashFowFormSet(data=self.request.POST)
if formset.is_valid():
forms = formset.save(commit=False)
for form in forms:
form.eom = end_of_month
form.user = self.request.user
form.save()
# return redirect(reverse_lazy("bird_list"))
return self.render_to_response({'formset': formset})
template:
<form id="form-container" method="POST">
{% csrf_token %}
{{ formset.management_form }}
<div class="empty-form">
{% for form in formset %}
{{ form.media.js }}
<p>{{ form }}</p>
{% endfor %}
</div>
<button id="add-form" type="button">+</button>
<button type="submit" class="btn btn-primary">Отправить</button>
</form>
<script>
let emptyForm = document.querySelectorAll(".empty-form")
let container = document.querySelector("#form-container")
let addButton = document.querySelector("#add-form")
let totalForms = document.querySelector("#id_form-TOTAL_FORMS")
let formNum = emptyForm.length-1
addButton.addEventListener('click', addForm)
function addForm(e) {
e.preventDefault()
let newForm = emptyForm[0].cloneNode(true) //Clone the form
let formRegex = RegExp(`form-(\\d){1}-`,'g') //Regex to find all instances of the form number
formNum++ //Increment the form number
newForm.innerHTML = newForm.innerHTML.replace(formRegex, `form-${formNum}-`) //Update the new form to have the correct form number
container.insertBefore(newForm, addButton) //Insert the new form at the end of the list of forms
totalForms.setAttribute('value', `${formNum+1}`) //Increment the number of total forms in the management form
}
</script>

Pop up message in Django

I have a form in Django where I upload many files and then perform some data processing on those files. I want to display a loader message while it's still processing in the backend.
I know we can use messages in django but it only shows after the processing is complete, I want to display a little animation while data is being processed. I didn't use ajax to post the form since it was easier with the simple method.
Is there any other way to achieve this?
Forms.py
class UploadFileForm(forms.Form):
file_A = forms.FileField(label= "Upload File-A ")
file_B = forms.FileField(label= "Upload File-B ")
year = forms.IntegerField()
Views.py
def display_uploadpage(request):
if request.method == 'POST':
form = BudgetForm(request.POST, request.FILES)
if form.is_valid():
file_A = form.cleaned_data["file_A"]
file_B = form.cleaned_data["file_B"]
year = form.cleaned_data["year"]
fs = FileSystemStorage()
file_A_name = fs.save(file_A.name, file_A)
file_B_name = fs.save(file_B.name, file_B)
p = ProcessData(year, file_A,file_A_name, file_B, file_B_name)
msg = p.process()
messages.info(request, msg )
return render(request, 'website/upload.html')
else:
form = UploadFileForm()
context = {'form': form}
return render(request, 'website/upload.html', context)
upload.html
<form method="post" enctype="multipart/form-data"> <!-- form method -->
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="btn btn-danger" id="upload">Upload</button>
</form>
I wanted to add this animation in the page while it's still processing.

Error while sending JavaScript generated image to Django ModelForm

I’m trying to use https://github.com/szimek/signature_pad to attach a signature to a form and send it to the server. I’ve been able to successfully upload images with a standard ImageField, and have also used szimek/signature_pad to download the signature. But when I try to get the signature to the server, I get "(Hidden field signature) No file was submitted. Check the encoding type on the form." So I think I’m at least successfully sending an image to the field, but am not sure how to encode it.
HTML
<form id="form" action="{% url ‘my_app:testFormPage' %}" method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<div id="signature-pad">
<canvas></canvas><br>
</div>
 <input type="hidden" name="signature" value=“signatureImage”>
<button type="submit" data-action="formSig">Submit</button>
</form>

Python
# Models.py
class testModel(models.Model):
name = models.CharField(max_length=50)
date = models.DateTimeField(default=timezone.now)
signature = models.ImageField (null=True, max_length=3000)
# Forms.py
class testForm(forms.ModelForm):
class Meta:
model = testModel
fields = ‘__all__’
widgets = { 'signature': forms.HiddenInput(),}
# Views.py
def testFormPage(request):
if request.method == 'POST':
form = testForm(request.POST, request.FILES)
if form.is_valid():
form.save()
return HttpResponseRedirect('/thanks/')
else:
form = testForm()
context = {'form': form}
return render(request, 'client_visits/testFormPage.html', context)
Javascript

The full javascript app can be found at https://github.com/szimek/signature_pad/tree/master/docs/js. Here’s just what I added
var formSig = wrapper.querySelector("[data-action=formSig]");
formSig.addEventListener("submit", function (event) {
var signatureImage = signaturePad.toDataURL();
});

Dynamically update Django form field options using Ajax to GET new queryset

I'm new to coding and django and I'm struggling to find the solution to the following problem having reviewed the answers I've found.
Im creating a search form with multiple fields. When the user selects the first field category (and before hitting search) I would like to dynamically change the queryset for the second field sub_category such that only related values are shown.
I have models.py as follows:
class Product(models.Model):
category = models.ForeignKey("Category")
sub_category = models.ForeignKey("SubCategory")
class Category(models.Model):
name = models.CharField(max_length=256)
class SubCategory(models.Model):
category = models.ForeignKey("Category")
name = models.CharField(max_length=256)
And my forms.py includes:
class BasicSearchForm(forms.Form):
category = forms.ModelChoiceField(
label='Category',
queryset=Category.objects.all(),
to_field_name="name",
empty_label=None,
initial="Red")
sub_category = forms.ModelMultipleChoiceField(
required=False,
label='Type',
queryset= SubCategory.objects.all(),
to_field_name="name",
widget=forms.Select)
And my views.py includes:
def search(request):
if request.method == 'POST':
form = BasicSearchForm(request.POST)
if form.is_valid():
category = form.cleaned_data['category']
sub_category = form.cleaned_data['sub_category']
return render(request, 'myapp/search.html', {'form': form})
else:
form = BasicSearchForm()
return render(request, 'myapp/search.html', {'form': form})
And finally the search.html includes:
<form class="search-form" role="search" action="/search/" method="get">
{{ form }}
<input type="submit" value="Search" />
</form>
I've played around with a few answers but nothing seems to work. I'd really appreciate some help. Thanks in advance!
Update:
Thanks for the feedback. As a result I updated the following:
In my urls.py:
urlpatterns = [
url(r'^ajax/update_subcategories/$', views.update_subcategories, name='update_subcategories'),
And in my views.py:
def update_subcategories(request):
category = request.GET.get('category', None)
sub_category = list(SubCategory.objects.filter(category__name__exact=category).values('name'))
return JsonResponse(sub_category, safe=False)
And I have this in my myapp/search.html:
{% block javascript %}
<script>
$("#id_category").change(function () {
var category = $(this).val();
$.ajax({
url: '{% url "myapp:update_subcategories" %}',
data: {
'category': category,
},
success: function (response) {
var new_options = response;
alert(new_options[0].name); // works
$('#id_sub_category').empty();
$.each(new_options, function(key, value) {
$('#id_sub_category')
.append($('<option>', { value : key })
.text(value.name));
});
}
});
</script>
{% endblock %}
Update: The sub_category options were showing as [object Object] until I changed value to value.name and it looks like it's working. I'll test it out and close unless there are any comments.
Update: Im still having an issue with the browser back button. When a user clicks back the dropdown values have changed back to the original queryset rather than the updated version.
You can't do this from Django views side, ie, backend. You could try an ajax request for implementing this kind of requests, by sending a GET request to the server for populating the drop-down or whatever you are into.
For a simple example, you could refer
here
How do I POST with jQuery/Ajax in Django?
EDIT
def update_subcategories(request):
category = request.GET.get('category', None)
sub_category = list(SubCategory.objects.filter(category__name__exact=category).values('name'))
return JsonResponse(dict(sub_category=sub_category))
Then in ajax response you could grab it like response.data.sub_category
Use ajax to send the category and retrieve subcategory elements.
For the category, send it via get request, and using the orm return the subcategories in a json format which you can show using jQuery.

How to use the value of <select> in with django function?

So I want to make a function with if in my html using django.
My function looks like :
function try() {document.getElementById("demo").inerHTML = '{%for x in xl%}'+
'{%if x.name == document.getElementById("select1").value%}'+
'<button type="button">hello</button>'+
'{%endif%}{%endfor%}'}
And the relevant html is :
<select id="select1">
<option value = "tiger"></option>
<option value = "bear"></option>
<option value = "eagle"></option>
</select>
<p id="demo"></p>
<script>try();</script>
So just to make it clear :
'xl' is a list, the items in this list have a name variable.
I want my web to show in the "demo" paragraph 'hello' buttons for each time that the selcted animal is the name of item in the list.
When trying to run this it says : " Could not parse the remainder: '("select1").value;' from 'document.getElementById("select1").value;' "
Please help me find what`s wrong and how to fix it, Thanks.
Why not just use a Django form, and then get the selected option value with JavaScript? Example code has not been tested. You still need an app within your Django project, settings, templating, routing, etc.
# forms.py
class AnimalForm(forms.Form):
TIGER = 'Tiger';
BEAR = 'Bear'
EAGLE = 'Eagle'
ANIMAL_CHOICES = (
(TIGER, TIGER,),
(BEAR, BEAR,),
(EAGLE, EAGLE,),
)
animal = forms.CharField(max_length=20, choices=ANIMAL_CHOICES,
default=TIGER)
def save(self):
return NotImplementedError
# implement
# views.py
from django.shortcuts import render
from .forms import AnimalForm
def choose_animal(request):
form = AnimalForm(request.POST or None)
if request.method == 'POST' and form.is_valid():
form.save()
# do something, like redirect to a success page, etc
return render(request, 'animal_form.html',
{'form': form})
#animal_form.html
<form action="." method="post" enctype="application/x-www-form-urlencoded">
{{ form.animal }}
<button type="submit">Save</button>
</form>
<p id="animal-selection"></p>
<script>
// assuming jQuery is already linked for brevity
(function($) {
$(function() {
$('#id_animal').on('change', function() {
$('#animal-selection').html($(this).val());
});
});
})(jQuery);
</script>

Categories

Resources