How to configure html for selectfield(wtforms) flask? - python

Good evening to everyone who reads this post.
I want to add a select box to my web site in flask, but i can not understand how to set up html for that
I look forward to see any comments and suggestions :)
My python code:
class selectmenu(Form):
month = SelectField('Choose month',choices=[('dec', 'dec'), ('yan', 'yan'), ('feb', 'febt')])
#app.route('/searchemp/', methods=['GET', 'POST'])
def searchemp():
form = selectmenu(request.form)
m = form.month.data
HTML:
<form action="" class="form-signin" method="post">
<h2 class="form-signin-heading" align="center">title</h2>
<input type="text" class="form-control"
placeholder= "username" name="username" value="{{request.form.username}}" required autofocus>
<!--
<input type="text" class="form-control"
placeholder= "month" name="month" value="{{request.form.month}}">
-->
<select name="month">
<option value="{{request.form.month}}">dec</option>
<option value="{{request.form.month}}">yanuary</option>
<option value="{{request.form.month}}">feb</option>
<option value="{{request.form.month}}">mar</option>
</select>
<button class="btn btn-lg btn-success btn-block" type="submit">Search</button>
<br>
<p align="center">{{error}} </p>
</form>

Jinja2 template engine will render selectfield with choices, you dont have to create a html select field, jinja2 already does. And if you need to check form submission use validate_on_submit() or request.method == 'POST':
class SelectMenu(Form):
month = SelectField('Select Month', choices=[(1, 'January'), (2,'February')])
#app.route('/searchemp/', methods=['GET', 'POST'])
def searchemp():
form = SelectMenu(request.form)
if form.validate_on_submit():
# get posted data
m = form.month.data
return render_template('index.html', form=form)
# index.html
<form action="" method="POST">
{{form.month.label}}{{form.month}}
</form>

Related

Need to show result on the same page - Django

I'm creating a password generator app. The app is working and stores the value on db.
The problem is whenever I refresh, the form resubmits and takes the previous value and stores.
Also, I want to show the email and password on the same page.
Whenever I refresh, I want to show an empty form with empty fields.
Views.py
def home(request):
if request.method=='POST':
inputemail = request.POST.get('InputEmail')
gen = ''.join(random.choices((string.ascii_uppercase+string.ascii_lowercase+string.digits+string.punctuation), k=10))
newpass = Item(email=inputemail,encrypt=gen)
newpass.save()
return render(request,'home.html',{"gen":gen})
return render(request,'home.html',{})
Home.html
<form method = 'post' id='pass-form' >
{% csrf_token %}
<div class="mb-3">
<label for="exampleInputEmail1" class="form-label">Email address</label>
<input type="email" class="form-control" name="InputEmail" >
<div id="emailHelp" class="form-text">We'll never share your email with anyone else.</div>
</div>
<button type="submit" name = "submit" class="btn btn-primary">Generate Password</button><br><br>
</form>
<div class="mb-3">
<label for="exampleInputPassword1" class="form-label">Generated Password</label>
<input type="text" id="InputPassword" name = "genpassword" value = {{gen}} >
</div>
Urls.py
urlpatterns = [
path('',views.home,name='home'),
]
According to docs:
you should always return an HttpResponseRedirect after successfully dealing with POST data. This tip isn’t specific to Django; it’s good web development practice in general.
So you should make another page to show generated password, which will take submitted instance id of Item model created in home view so:
def home(request):
if request.method=='POST':
inputemail = request.POST.get('InputEmail')
gen = ''.join(random.choices((string.ascii_uppercase+string.ascii_lowercase+string.digits+string.punctuation), k=10))
newpass = Item(email=inputemail,encrypt=gen)
newpass.save()
return redirect('success', args=(newpass.pk))
return render(request,'home.html',{})
def success(request, pk):
item_obj = get_object_or_404(Item, pk=pk)
return render(request,'success.html', {'gen':item_obj.encrypt})
urls.py
urlpatterns=[
path('',views.home,name='home'),
path('success/<int:pk>/',views.success,name='success')
]
success.html
<body>
<h2>The form is successfully submitted.</h2>
<br>
<div class="mb-3">
<label for="exampleInputPassword1" class="form-label">Generated Password</label>
<input type="text" id="InputPassword" name="genpassword" value={{gen}} >
</div>
Again go to password generator page.
</body>
Another possible solution
You can make email field required in Html form and then hard refresh the page after submitting the form using Javascript's submit event so the template:
<form method='POST' id='pass-form'>
{% csrf_token %}
<div class="mb-3">
<label for="exampleInputEmail1" class="form-label">Email address</label>
<input type="email" class="form-control" name="InputEmail" required>
<div id="emailHelp" class="form-text">We'll never share your email with anyone else.</div>
</div>
<button type="submit" class="btn btn-primary">Generate Password</button><br><br>
</form>
<div class="mb-3">
<label for="exampleInputPassword1" class="form-label">Generated Password</label>
<input type="text" id="InputPassword" name = "genpassword" value ={{gen}} >
</div>
<script type='text/javascript'>
let form = document.getElementById('pass-form');
addEventListener('submit', (event) => {
location.reload(true); // hard refreshed
console.log('hard refreshed')
});
</script>
Note: Then also there are certain browsers like Microsoft Edge which gives pop up as Resubmit the form? in which they mention The page you're looking for used information that you entered. Returning to the page might trigger a repitition of any action you took there. Do you want to continue?
The moment you click on continue it creates duplicacy of records, so I think as docs mentions the first approach is better.

I am trying to save the form data. My Django form data is not saved, why?

I am trying to save form data from Django template to Django Model. Its not throwing any error but its not saving the data as well
Could you please let me know what could be the problem and how should I solve?
Here is my Django form template:
<form method="POST" class="review-form" autocomplete="on">
{% csrf_token %}
<div class="rating-form">
<label for="rating">Your Overall Rating Of This Product :</label>
<span class="rating-stars">
<a class="star-1" href="#">1</a>
<a class="star-2" href="#">2</a>
<a class="star-3" href="#">3</a>
</span>
<select name="rating" id="rating" required=""
style="display: none;">
<option value="">Rate…</option>
<option value="3">Average</option>
<option value="2">Not that bad</option>
<option value="1">Very poor</option>
</select>
</div>
<textarea cols="30" rows="6"
placeholder="What did you like or dislike? What did you use this product for?" class="form-control"
id="review" name="description"></textarea>
<div class="row gutter-md">
<div class="col-md-12">
<input type="text" class="form-control"
placeholder="Your Name - This is how you'll appear to other customers*" id="author" name ="name">
</div>
</div>
<button type="submit" class="btn btn-dark">Submit Review</button>
</form>
My Forms.py
class ReviewForm(forms.ModelForm):
class Meta:
model = Reviews
fields = ('rating', 'description', 'display_name')
My Views:
def reviews(request, slug):
if request.method == "POST":
if request.user.is_authenticated:
form = ReviewForm(request.POST)
if form.is_valid():
review = form.save(commit=False)
review.product = Products.objects.get(slug=slug)
review.user = request.user
review.display_name = request.name
review.description = request.description
review.rating = request.rating
print(review)
review.save()
messages.success(request, "Review saved, Thank you for the feedback.")
return redirect('products:products')
else:
messages.error(request, 'Sorry! Only customer purchased this Item are eligible for the review')
else:
pass
return redirect('ecommerce:products')
Try using generic ClassBasedViews. It's worth it to learn the concept! You will have to write less code and you will be able to edit a model instance and delete it from the front end.

How to get selected value in dropdown list, then pass it to views.py

I'm working on an upload file feature with dropdown and dropzone. But, whenever I submit the uploaded file with selected option, it always says that the selected option is None. I found it None after I printed the nama_bimbingan in views.py. Here it is my code.
url.py
....
url(r'bimbingan/add/upload', mengelola_bimbingan.upload_data_bimbingan, name='add-bimbingan-excel'),
url(r'bimbingan/download-template/', mengelola_bimbingan.bimbingan_template, name='bimbingan-template'),
....
forms.py
class UploadBimbinganForm(forms.Form):
...
...
dropdown_choices = tuple(zip(all_pembimbing, all_pembimbing))
nama_pembimbing = forms.ChoiceField(choices = dropdown_choices)
upload_bimbingan.html
<form method="POST" action="{% url 'app:add-bimbingan-excel' %}" enctype="multipart/form-data">
{% csrf_token %}
<div class="py-3">
<label for="id_nama_pembimbing"> Nama Pembimbing Akademik: </label>
<select class="form-control mb-2" id="id_nama_pembimbing" name="nama_pembimbing" required>
<option value = "" selected="selected">---------</option>
<option value = {{form.nama_pembimbing}}></option>
</select>
</div>
<div id="myDropzone" class="dropzone" drop-zone>
<h6 class="dz-message"> Drop file here or click to upload</h6>
</div>
<div class="py-3">
Download Template<br>
<div class="row justify-content-between py-3">
<div class="col-md-5 mb-1">
<a href="{% url 'app:read-all-bimbingan' %}" class="btn btn-blue-outlined">Batal</a
</div>
<div class="col-md-5">
<input type="submit" value="Simpan" class="btn btn-block btn-blue">
</div>
</div>
</div>
</form>
views.py
#login_required(redirect_field_name='index')
#user_passes_test(only_admin_access)
def upload_data_bimbingan(request):
form = UploadBimbinganForm(request.POST or None)
if request.method == "POST" and 'file' in request.FILES:
nama_pembimbing = request.POST.get('nama_pembimbing')
excel_file = request.FILES["file"]
data = get_data(excel_file, column_limit=1)
bimbingans = data["Bimbingan"]
...
...
if(len(duplicate) == 0):
space_parsed_query = nama_pembimbing.replace(' ', '%20')
cleaned_query = space_parsed_query.replace(',', '%2C')
nip_pembimbing = int(get_data_dosen_by_nama(cleaned_query)[0]["nomor"])
for bimbingan in bimbingans:
if(bimbingan[0] != "NPM"):
new_bimbingan = Bimbingan(nip_pembimbing=nip_pembimbing, npm_mahasiswa=bimbingan[0])
new_bimbingan.save()
return redirect('/app/bimbingan')
else:
...
...
return redirect('/app/bimbingan')
else:
context={
"form": form
}
return render(request, 'app/mengelola_bimbingan/upload_bimbingan.html', context)
I already tried to use nama_pembimbing = form.cleaned_data["nama_pembimbing"] in views.py, but it's still not working since the form.is_valid() always return false, so I removed it. I use django & python for this and purpusely don't use javascript to handle the uploaded file & selected option. I really hope that someone can help me to resolve this issue.
I think this part of your html code is just messed up.
<select class="form-control mb-2" id="id_nama_pembimbing" name="nama_pembimbing" required>
<option value = "" selected="selected">---------</option>
<option value = {{form.nama_pembimbing}}></option>
</select>
I recommend you not to give whitespace between html attribute and its value. So, it should be like this:
<select class="form-control mb-2" id="id_nama_pembimbing" name="nama_pembimbing" required>
<option value="" selected="selected">---------</option>
<option value="{{form.nama_pembimbing}}">{{form.nama_pembimbing}}</option>
</select>
I already got a solution for this issue. The problem is on dropzone. I tried to remove dropzone and the selected value from dropdown can be retrieved in views. So, to solve this issue, I need to add the following codes inside my dropzone script.
init: function() {
dzClosure = this;
this.on("sending", function(data, xhr, formData) {
formData.append("nama_pembimbing", jQuery("#id_nama_pembimbing").val());
});
}
That's all and it should be fuctioned well.

Why I am getting Bad request error for this flask page?

I have two flask form in same page. One form is visible at the beginning and user have to select an option and based on that the second form is generated. Second from contains a dropdown which will submit the form on onchange event. When this submission occurs I am getting bad request error. My Html form is:
<form action="/ip" method="POST" name="btn" value="project">
<label>Select Project : </label>
<select class="form-control" style="width: 50%;display:inline-block" name="project_name">
<option></option>
<option value="k">Ki</option>
<option value="s">S</option>
<option value="l">L</option>
</select>
<button type="submit" class="btn btn-primary m-b-10 m-l-5" style="display:inline-block" ">Fetch Details</button>
</form>
<form method="POST" action="/ip" name="btn" value="dlvr">
<select id="subsystem_value" onchange="this.form.submit()">
{% for i in data %}
{% for k in i %}
<option value={{ k }}>{{ k }}</option>
{% endfor %}
{% endfor %}
</select>
</form>
and my flask view is :
#auth.route('/ip',methods = ['POST', 'GET'])
def ip():
if request.method == 'POST':
if request.form['btn'] == "project":
project = request.form['project_name']
c, conn = connection()
subsystem = "SELECT distinct sub from ip where project='{}'".format(project)
query = "SELECT distinct del from ip where project='{}'".format(project)
c.execute(query)
data = c.fetchall()
c.execute(subsystem)
subsystem = c.fetchall()
sub = []
for row in subsystem:
for id in row:
sub.append(id)
conn.close()
return render_template('ip.html', data=data,sub=sub)
else:
subsystem = request.form['subsystem_value']
return render_template('ip.html')
else:
return render_template('ip.html')
I tried to make same name for forms and gave separate values too. But still I am getting bad request error.
I have two areas where your error is coming from
1) Form name is deprecated since HTML 4 and is no longer submitted therefore
if request.form['btn'] == "project":
will not be understood by flask
The way to go around that is to give your submit button a name like this
<button type="submit" name="project" class="btn btn-primary m-b-10 m-l-5" style="display:inline-block" ">Fetch Details</button>
and in your flask view, check for the form like this
if 'project' in request.form:
2) The second error is on this line
<form method="POST" action="/ip" name="btn" value="dlvr">
<select id="subsystem_value" onchange="this.form.submit()">
line two here should be name= "subsystem_value", not id="subsystem_value"
otherwise this line in flask will not be understood
subsystem = request.form['subsystem_value']
So I have this simplified code that is no longer giving me an error and returning the values the way I think you want them
in flask
#app.route('/ip',methods = ['POST', 'GET']) #Used #pp.route to match my testing app
def ip():
if request.method == 'POST':
if 'project' in request.form:
project = request.form['project_name']
return str(project)
else:
subsystem = request.form['subsystem_value']
return str(subsystem)
else:
return render_template('test.html')
in the template
<form action="/ip" method="POST" >
<label>Select Project : </label>
<select class="form-control" style="width: 50%;display:inline-block" name="project_name">
<option></option>
<option value="k">Ki</option>
<option value="s">S</option>
<option value="l">L</option>
</select>
<button type="submit" name="project" class="btn btn-primary m-b-10 m-l-5" style="display:inline-block" ">Fetch Details</button>
</form>
<form name method="POST" action="/ip" >
<select name="subsystem_value" onchange="this.form.submit();">
<option value="test1">t1</option>
<option value="test2">t2</option>
<option value="test3">t3</option>
</select>
</form>
Hope that helps you out
You are in the perfect position to avail yourself of Flasks debug facilities, which you can activate by either setting the environment variable FLASK_DEBUG=1 or by passing debug=True to app.run().
See http://flask.pocoo.org/docs/1.0/api/#flask.Flask.debug
Also, if there's any chance that this code will face hostile users, use SQL bind variables instead of constructing a query from untrusted input. A SQL Injection attack can ruin your day.

Display selected form items in another page with Flask

I'm using Flask 0.12 with Python 3.6 to create a simple app that will display selected items in another page when the submit button is clicked.
The main Flask app is in app.py as:
from flask import Flask, render_template
app = Flask(__name__)
#app.route('/')
def index():
return render_template('index.html')
#app.route('/result', methods=['POST'])
def result():
return render_template('result.html')
This renders the following webpage using Bootstrap:
<h1>Example Page</h1>
<p>Choose the options in the form below then submit your selections.</p>
<form action="">
<div class="form-group">
<label for="vehicle">Vehicle</label>
<select id="vehicle" class="form-control">
<option>truck</option>
<option>car</option>
<option>van</option>
</select>
</div>
<div class="form-group">
<label for="year">Year</label>
<select id="year" class="form-control">
<option>1972</option>
<option>1999</option>
<option>2010</option>
</select>
</div>
</form>
<br>
<button type="submit" class="btn btn-default">Submit</button>
How can I get Flask to show the selected items in my results.html template when the submit button is clicked?
You have to make few changes in the form to display in result page.
You have to add action url and method in form
<form action="/result" method="post">
Add name in the select field
<select id="vehicle" class="form-control" name="vehicle">
<select id="year" class="form-control" name="year">
Use flask request to get the form values
from flask import request
# inside your POST view
vehicle = request.form.get('vehicle')
year = request.form.get('year')
return render_template('result.html', vehicle=vehicle, year=year)
Finally in your result html page add these...
{{ vehicle }} {{ year }}

Categories