Passing parameters from webpage to server (Flask) - javascript

I'm just getting started with adding a backend into my front-end code and think flask is a good framework to start learning with.
One of the things I'm having trouble with is submitting information to the server for processing. Specifically here I have a list of radio buttons, and I want to send to a server a list of all the radio buttons the user checked when he or she hit submit. The server then processes that information and returns a new page.
This is the form:
<form action="{{ url_for('timeline') }}" method="post">
{% for each_tag in tags %}
<div class="checkbox">
<label>
<input type="checkbox" name="channel[]" value="{{each}}" >
{{each_tag}}
</label>
</div>
{% endfor %}
<button type="submit"> submit </button>
</form>
Here are the relevant functions in the main flask file:
#app.route('/')
#app.route('/index.html')
def checklist():
for rownum in range(1,sh.nrows):
row_values = sh.row_values(rownum)
all_tags.add(row_values[7])
return render_template('index.html', tags=all_tags)
#app.route('/timeline.html', methods=['POST','GET'])
def timeline(request):
//do stuff with list of checked radio buttons
return render_template('timeline.html')
I'm not exactly sure how information is passed back and forth. I can send server info to the html templates and I think once I get this example down and figure out how information is passed the other direction I can start doing some interesting things. =)

Naming the checkboxes with trailing square brackets ("channel[]") is a PHP thing, Flask doesn't need that.
Just use the same name in all the checkboxes:
<form action="{{ url_for('timeline') }}" method="post">
{% for each_tag in tags %}
<input type="checkbox" name="channel" value="{{each}}" >
{% endfor %}
<button type="submit"> submit </button>
</form>
Then to retrieve the array of selected values use request.form.getlist():
#app.route('/timeline.html', methods=['POST','GET'])
def timeline(request):
checked = request.form.getlist('channel')
# do something with checked array
return render_template('timeline.html')

Related

Submit Button disabled if file doesn't upload in Django

Currently working on a Django project where I am stuck in a situation and the scenario is something like that I have two forms in my abc.html page, one is used for input file and second is used to run python script internally. But the issue is even if I don't input the file the submit button "run python script" start's working without submitting a file. Here I want to create a check that submit button "run python script" will run only at one condition when file will submitted otherwise button will disable. It will active only at one condition when user will input the file.
I am sharing the details:
abc.html:
<!--form to input file -->
<form method="post" enctype="multipart/form-data" name="myform">
{% csrf_token %}
<input type="file" id="file" name="doc" class="inputfile" onchange="document.myform.submit()"> </form>
<-- end of input file-->
<!-- form to run python script -->
<form action = "/results/" method="post" id="subform">
{% csrf_token %}
<input type="submit" id="btnSubmit" name="doc" value="run python script" class="btn btn-warning btn-sm" />
</form>
<-- end of form running python script -->
views.py:
def compliance_check(request): #function to upload file
global uploaded_file
if request.method == 'POST':
uploaded_file = request.FILES['doc']
print(uploaded_file.name)
print(uploaded_file.size)
fs = FileSystemStorage()
fs.save(uploaded_file.name, uploaded_file)
messages.info(request, 'your file ' + uploaded_file.name + " has been uploaded successfully")
return render(request, 'enroll/abc.html')
def results(request): #function to run python script
user_id = request.session['user_id']
hash_id, id_exists = compliance(user_id)
request.session['hash_id'] = hash_id
if id_exists:
messages.info(request, "This File has already been analyzed")
return redirect(tables_view)
I have tried multiple ways to create a check but not succeed yet. I hope that everyone will understand the question and the scenario is simple that there should be a check before clicking on run script button that please select the file first. The button should run only at one condition if user upload file.

How to stay in the same page after submiting form without disabling the action (HTML/Flask)

I wrote an HTML template to send an email using Flask. In the HTML script, I have a form that has a "send" button and once it's clicked, it triggers an email in Flask.
HTML Script
<form class="form-container" action="{{ url_for('send_email') }}">
<div class="form-group">
<label for="to-address">To </label>
<input id= "to-address" name="to-address" type="email"
placeholder="sample#email.com" class="form-input">
</div>
<div class="form-group">
<label for="title">Title</label>
<input id= "email-title" name="email-title" type="text" placeholder="Title"
class="form-input">
</div>
<div class="form-group">
<label for="message">Message</label>
<textarea id= "email-body" name="email-body" placeholder="Send Message" class="form-
text-area"></textarea>
</div>
<button id="email-send-btn" type ="submit" class="btn btn-primary"> Send </button>
</form>
FLASK
#application.route('/send_email')
def send_email():
to_address = request.args.get('to-address')
subject = request.args.get('email-title')
text = request.args.get('email-body')
msg= Message(
subject,
sender="abc#email.com",
recipients=to_address,
)
msg.html = render_template("email.html", text=text)
mail.send(msg)
return("success")
The email itself is working well but I have an issue with redirecting the page after clicking the "Send" button. Once I click on the Send button, whose id="email-send-btn", I want to stay in the current page, probably showing a notification popup to indicate the email has been sent successfully. I put return('success)` in the last line of my Flask script, because I had to return something to avoid a blank page.
I tried this following to stay in the same page after hitting the Send button. It allows me to stay in the same page, but also blocks the action completely and doesn't send any email. Is there any way to stay in the same page after clicking the send button without blocking the action of sending email?
$(document).ready(function(){
var $form = $('form');
$form.submit(function(){
$.post($(this).attr('action'), $(this).serialize(), function(response){
// do something here on success
},'json');
return true;
});
});
Historically returning false from a submit handler prevented form submission without needing to call submit event object methods such as preventDefault and/or stopPropagation
With careful reading you may be able to infer that jQuery documentation says the same thing:
If you'd like to prevent forms from being submitted unless a flag variable is set ... [return the value of the flag from the submit handler added using the jQuery .submit(handler) syntax]
means that if the flag variable is set true, form submission is not prevented.
Hence return false instead of true to stay on the page, letting jQuery handle cross browser compatibility issues.
You can use render template + flash message.
https://flask.palletsprojects.com/en/2.2.x/tutorial/templates/
https://flask.palletsprojects.com/en/2.2.x/patterns/flashing/
from flask import render_template, flash
... your code here ...
flash('Email has been sent successfully.')
return render_template('yourtemplate.html')
And in your template you have to put this code, like in documentation:
% with messages = get_flashed_messages() %}
{% if messages %}
<ul class=flashes>
{% for message in messages %}
<li>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
{% endwith %}
Of course you can use any HTML tag instead of unordered list with items.
Right now you just use another callback that does something when the form submits but you don't block the standard submitting. In order to achieve that you should managed the event defining that he should "prevent default" actions.
$form.submit(function(e){ //< add here "e" parameter
e.preventDefault(); //< add this
$.post($(this).attr('action'), $(this).serialize(), function(response){
// do something here on success
},'json');
return false; //< change this
});

Populating dependent dropdown list using Python and Flask

I have a web app with a form which takes two inputs, a file name and a sprint number.
The first one, which takes the file name, is a dynamically populated list which retrieves the list of CSV files in a specific directory and populates the form list accordingly.
Each of those CSV files has some duplicate sprint numbers in them (like 2012, 2027 etc). After selecting from the first drop down, I want the second drop down list to populate with a list of all the unique sprint numbers from the chosen CSV file name. These unique sprint numbers could probably be generated using a python script, and then results must somehow be used to populate the second drop down list.
See picture for a better idea.
Webpage view
Does anyone know how to approach this?
<form action="{{ url_for('output_burndown_chart') }}" method="post">
<label for="file_name">File Name:</label><br>
<!-- <input type="text" name="file_name"><br><br> -->
<select id="file_name" name="file_name">
{% for i in dir_files %}
<option value="{{ i }}">{{ i }}</option>
{% endfor %}
</select>
<br>
<br>
<label for="sprint_number">Sprint Number:</label><br>
<input type="text" name="sprint_number"><br><br>
<input type="submit">
</form>
#app.route('/burndown', methods=['GET','POST'])
def output_burndown_chart():
if request.method == "POST":
sprint_num = request.form['sprint_number']
file_name = request.form['file_name']
dir_name = "./files"
file_path = os.path.join(dir_name, file_name)
df_final = burndown_gen(file_path, sprint_num)
return render_template('test.html', df_final=df_final, sprint_num=sprint_num)
elif request.method == 'GET':
dir_files = os.listdir('./files/')
print(dir_files)
return render_template('burndown_form.html',dir_files=dir_files)

How to handle changing boolean field from database by ajax?

There is a piece of my html:
<form action="" method="post">
{% csrf_token %}
{% if donate.is_taken == False %}
<br>
<button type="submit" class="btn" name="taken_or_not" value="not_taken">Mark as taken</button>
{% else %}
<button type="submit" class="btn" name="taken_or_not" value="taken">Mark as not taken</button
{% endif %}
</form>
There is a model:
class Donation(models.Model):
...
...
is_taken = models.BooleanField(default=False)
How to create a ajax request, that the user is able to change the value 'taken_or_not' by a single button both on the page and in the database. Without any redirects, server loading etc.
I am struggling to get it.
Thanks for help.
Make a route that will take the the donation id and return it's "is_taken".
Make a repeating call using ajax to the particular route.

Dynamically generate client-side HTML form control using JavaScript and server-side Python code in Google App Engine

I have the following client-side front-end HTML using Jinja2 template engine:
{% for record in result %}
<textarea name="remark">{{ record.remark }}</textarea>
<input type="submit" name="approve" value="Approve" />
{% endfor %}
Thus the HTML may show more than 1 set of textarea and submit button.
The back-end Python code retrieves a variable number of records from a gql query using the model, and pass this to the Jinja2 template in result. When a submit button is clicked, it triggers the post method to update the record:
def post(self):
if self.request.get('approve'):
updated_remark = self.request.get('remark')
record.remark = db.Text(updated_remark)
record.put()
However, in some instances, the record updated is NOT the one that correspond to the submit button clicked (eg if a user clicks on record 1 submit, record 2 remark gets updated, but not record 1).
I gather that this is due to the duplicate attribute name remark. I can possibly use JavaScript/jQuery to generate different attribute names. The question is, how do I code the back-end Python to get the (variable number of) names generated by the JavaScript?
Thanks.
edited
Inside the template for loop use loop.index: the current iteration of the loop.
Then:
{% for record in result %}
<textarea name="remark{{ loop.index }}">{{ record.remark }}</textarea>
<input type="submit" name="approve" value="{{ loop.index }}" />
{% endfor %}
return:
<textarea name="remark1">first record remark</textarea>
<input type="submit" name="approve" value="1" />
<textarea name="remark2">second record remark</textarea>
<input type="submit" name="approve" value="2" />
<textarea name="remark2">third record remark</textarea>
<input type="submit" name="approve" value="3" />
and in your backend code:
def post(self):
if self.request.get('approve'):
updated_remark = self.request.get('remark' + self.request.get('approve'))
record.remark = db.Text(updated_remark)
record.put()
I wrote this without testing it. Probably doesn't work, but could give you a hint.
new [better] solution
put each couple of textarea and input inside an form:
{% for record in result %}
<form>
<textarea name="remark">{{ record.remark }}</textarea>
<input type="submit" name="approve" value="Approve" />
</form>
{% endfor %}

Categories