Capture values from multiple select form and POST via Flask [duplicate] - python-3.x

This question already has answers here:
Converting Flask form data to JSON only gets first value
(2 answers)
Closed 4 years ago.
I need to capture multiple select form vlaue (generated from a MongoDB collection ) and POST via a Flask route to another MongoDB collection: recipes
Below is the relevant form div:
<form action="{{ url_for('insert_recipe') }}" method="POST" class="col s12">
...
<div class="input-field col s6 l6">
<i class="material-icons prefix">warning</i>
<select multiple id="allergen_name" name="allergenlist">
<option value="" disabled selected>Choose allergens</option>
{% for allergen in allergens %}
<option value="{{allergen.allergen_name}}">{{allergen.allergen_name}}</option>
{% endfor %}
</select>
</div>
</div>
...
</form>
I want to capture the selected options and POST them via Flask:
# Get all recipes
#app.route('/get_recipes')
def get_recipes():
return render_template("recipes.html",
recipes=mongo.db.recipes.find())
# Render HTML form
#app.route('/add_recipe')
def add_recipe():
return render_template('addrecipe.html',
users=mongo.db.users.find(),
allergens=mongo.db.allergens.find(),
cuisines=mongo.db.cuisine.find(),)
# Send the form
#app.route('/insert_recipe', methods=['POST'])
def insert_recipe():
recipes = mongo.db.recipes
recipes.insert(request.form.to_dict())
return redirect(url_for('get_recipes'))
However, only the first selected option is being captured and sent.
Any help would be appreciated.
EDIT:
When looking at: http://werkzeug.pocoo.org/docs/0.12/datastructures/#werkzeug.datastructures.MultiDict.to_dict
... relaised that I need to set to_dict(flat=false) in order to have all values of dict returned.

See EDIT above, the correct way is to:
# Send the form
#app.route('/insert_recipe', methods=['POST'])
def insert_recipe():
recipes = mongo.db.recipes
recipes.insert_one(request.form.to_dict(flat=False))
return redirect(url_for('get_recipes'))
Also, just found a duplicate as notified by #davidism :
Converting Flask form data to JSON only gets first value

Related

A Simple Calculator using Django

I want to create a website where the user is asked to type a given number to get the square number and the square root.
This is from index.html:
<div class="d-flex typeW">
<form action="add">
Enter a number : <input type="text" name="num1">
<input type="submit">
</form>
</div>
This is from the result page (where you can see the result):
<div class="d-flex title2">
<h2>
{% block content %}
{{result}}
{% endblock %}
<br><br>
This is from view:
def add(request):
num1 = int(request.GET["num1"])
return render(request, 'result.html' , {result2: num1 * num1})
Now I want to take the square root of that number but I'm not sure how.
How do I take one input and then do two calculations by using two functions?
help much appreciated
Simply do two calculations in your view and return both results within the context. You can then access all values in the context and render them in the template.
import math
def add(request):
# Get the user input
num1 = int(request.GET["num1"])
# Calculate square
num1_square = num1 ** 2
# Calculate root
num1_root = math.sqrt(num1)
# return context
context = {
'square': num1_square,
'root': num1_root
}
return render(request, 'result.html' , context)
# template
<div class="d-flex title2">
<h2>
{% block content %}
{{ square }}
{{ root }}
{% endblock %}
<br><br>

how can I get the sum of all expense based on current logged user in django?

I am using to sum all the expense values which are assigned to an user. I am not able to display it in my webpage. How can i do that?
The models.py code is as follows:
class expense(models.Model):
Expensecat=(('food','Food'),
('transportation','Transportation'),
('education','Education'),
('health','Health'),
('clothes','Clothes'),
('beauty','Beauty'),
('hosuehold','Household'),
)
ExpenseAmount=models.FloatField(max_length=100)
Category=models.CharField(max_length=200,choices= Expensecat)
Description=models.TextField(max_length=200)
Date=models.DateTimeField(default=timezone.now)
user=models.ForeignKey(User,on_delete=models.CASCADE)
Views.py
def home(request):
try:
expense_total = expense.objects.filter(user=request.user).aggregate(expenses=Sum('ExpenseAmount'))
except TypeError:
print('No data')
data = {
'Expense':expense_total['expenses'],
}
return render(request, 'budget/home.html', data )
HTML CODE:
<div class="col-lg-3 col-md-6 d-flex stat my-3">
<div class="mx-auto">
<h6 class="text-muted">Expense</h6>
<h3 class="font-weight-bold">{{ Expense.expenses }}</h3>
<h6 class="text-success"></h6>
</div>
You assign this to the Expense variable, so you render this with Expense, so not Expense.expenses, you already "unwrapped" the value from the dictionary:
{{ Expense }}
Note: When you make calculations with money, it is better to use a DecimalField [Django-doc],
not a FloatField [Django-doc]. Floats can generate rounding errors when you perform calculations.
You can also use django-money [GitHub] to specify a MoneyField. This has also specifies a currency, and can convert money to a different
currency.

Flask grid edit using wtforms

I'm working on a project that pulls a list of all the spirits listed in the Oregon State liquor pricing sheet and stores it in a table in my flask app. The goal is to be able to let moderators see the list and check a box next to each spirit to designate if it is whiskey or not.
It's my first time really using flask, but I've gone through a book about flask twice now to try and understand it, so this is me trying to build my own thing.
Right now, if I check a box and then hit submit all the records are switched to is_whiskey = False instead of each one being done individually.
Here's my model:
class Whiskies(db.Model):
__tablename__ = 'whiskies'
id = db.Column(db.Integer, primary_key=True)
ols_name = db.Column(db.String(64), unique=True)
display_name = db.Column(db.String(64), unique=True, index=True)
display_distiller = db.Column(db.String(64), unique=False)
is_whiskey = db.Column(db.Boolean, default=True)
reviews = db.relationship('Review', backref='review', lazy='dynamic')
Here's my view:
#main.route('/update-whiskies', methods=['GET', 'POST'])
#login_required
#permission_required(Permission.MODERATE)
def update_whiskies():
whiskies = Whiskies.query.all()
is_whiskey_form = IsWhiskeyForm()
submitpageform = SubmitPageForm()
if submitpageform.validate_on_submit():
for w in whiskies:
w.is_whiskey = is_whiskey_form.is_whiskey.data
db.session.update(w)
db.session.commit()
flash("You updated a bunch of whiskies")
return redirect(url_for('.index'))
return render_template('update_whiskies.html', whiskies=whiskies,
is_whiskey_form=is_whiskey_form,
submitpageform=submitpageform)
Here's my .html page:
{% extends "base.html" %}
{% import "bootstrap/wtf.html" as wtf %}
{% block page_content %}
<div>
{% for whiskey in whiskies %}
<li class="whiskey">
{% if whiskey.display_name %}
{{ whiskey.display_name }}
{% else %}
{{ whiskey.ols_name }}
{% endif %}
{{ is_whiskey_form.is_whiskey.label }}
{{ is_whiskey_form.is_whiskey(value=whiskey.is_whiskey) }}
</li>
{% endfor %}
{{ wtf.quick_form(submitpageform) }}
</div>
{% endblock %}
Here are my forms:
class IsWhiskeyForm(Form):
"This is intended for use in bulk editing whiskies"
is_whiskey = BooleanField("Is Whiskey", default="checked")
class SubmitPageForm(FlaskForm):
"This is intended for submitting a batch edit"
submit = SubmitField('Update Whiskies')
This is what the page currently looks like. I want to be able to check a box and hit submit and then have it reflected in the db.
Thanks a lot to whoever is up to helping me with this. I've been stuck about a week and I just need to get past this hump to finish up my module.
I had a similar task to solve: producing a list of database records (1 record per row) and let the user choose one record. So I put a radiobox at the end of each row. The problem was how to inform the Flask app which row was checked. I came up with the following solution:
You must make the submit button of the form trigger a POST request
You need in the data you want to show in the browser one field which is unique so you can use it to identify a row (I had data from an SQL database to display, so the primary key of a record was a good solution)
Add a radiobutton in your html-template inside the {% for ... %} loop like this:
{% for data in dataset.items %}
... display the data of the row, plus:
<div>
<input type="radio" class="form-check-input cursor-pointer"
name="check_line" value="{{ data._id }}">
</div>
{% endfor %}
in the POST request data there will appear a name-value pair produced by the radiobuttons which consists of the name you provided (here: "check_line") and the value you provided. The trick is that the value can be used to identify the row (is unique) because the Flask-rendering-magic was used.
By the way: when testing POST-requests I often write:
if request.method == 'POST':
print(request.values)
in the route-functions where POST needs to be handled. This will display all the POST input parameters on the Flask-console.
Try this
if submitpageform.validate_on_submit():
for w in whiskies:
w.is_whiskey = is_whiskey_form.is_whiskey.data
db.session.commit()
Remove db.session.update(w)

How to make dropdown list change a table data with Jinja2 + Flask

I'm using Jinja2 Template to change dynamically a result table for my Motor Racing webapp. It's not perfect, but I'm making my way with patience.
I have a template that is rendered by the URL 'webapp.com/driver/' that's supposed to show the results of a Race where the driver was present inside a table. To make it clear:
The user selects a Driver and goes to webapp.com/driver/someDriver
The someDriver page has a dropdown list with ALL Races the someDriver has been through
User selects someRace from dropdown list
Table is fed by someRace's results
The python flask route I wrote for it:
#app.route('/driver/<driverid>')
def driver(driverid):
driver = db.Drivers.find_one({'_id': ObjectId(driverid)})
races = db.Races.find({'finalresult.driver':driver['unique_name']}).sort([('timestamp', -1)])
racesList = []
for race in races:
raceItem = {
'filename':race['filename'],
'date':datetime.datetime.fromtimestamp(float(race['timestamp'])).strftime('%d-%m-%Y'),
'finalresult':race['finalresult'],
'id':str(race['_id'])}
racesList.append(raceItem)
return render_template('user.html', driver=driver, racesList=racesList)
Now I'm trying to make a dynamic template that changes the Result table everytime the user change the selection.
<div class="row">
<form name="racesForm">
<label for="selRace">Escolha uma corrida!</label>
<select class="form-control" id="selRace">
{% for race in racesList %}
<option value="{{race.filename}}">
{{race.filename}}
</option>
{% endfor %}
</select>
</form>
<hr>
</div>
<div class="row">
<table>
<thead>
<th>Position</th>
<th>Driver</th>
</thead>
<tbody>
<tr>
{% position, drivername in race.finalresult %}
<th>{{position}}</th>
<td>{{drivername}}</td>
{% endfor %}
</tr>
</tbody>
</table>
</div>
But now I'm receiving a error:
Encountered unknown tag 'position'.
And that's it..I'm not sure of how to make this dropdown list change the table dynamically. Any insights 'd be aprecciated.
UPDATE//Giving more info:
Driver is a very simples dict/json that has two keys ['name'] and ['_id']
racesList is an array of many "raceItem"s.
Each "raceItem" has a key anmed 'finalresult' that has data of the positions each driver has finished.
this array is filled with many objects it may seem like the example below:
'finalresult': [
{'position': 1,
'drivername': 'John Doe'},
'position': 2,
'drivername': 'Foo Bazz', etc
}]
As I told before, I want this data to be displayed in a table, depending on what RACE has been selected from the "raceList" dropdown list.
As a solution, I'm thinking of creating a new routing...but I wanted this routing to be displayed in the same page. I don't want the user to be directed to a new window.
First of all, you are getting Encountered unknown tag 'position' as you are using a different data structure. As you mentioned finalresult is a list of dicts. So you need to iterate through it when populating your table.
{% for driver_stat in race.finalresult %}
<td>{{driver_stat.position}}</td>
<td>{{driver_stat.drivername}}</td>
{% endfor %}
But with your approach, this table will not be updated dynamically as you select different race from your dropdown. Instead I suggest to use jquery. So you don't have to nevigate to another page to display the driver stats. I found several useful SO question that have been already answered on this. Follow them.
Ref:
Populate table based in select
Populate HTML table based on second dropdown selection

Is it possible to send an advanced query to Shopify /search url

I am customizing a Shopify template has a form like this.
<form action="/search" method="get" class="search-bar" role="search">
<input type="hidden" name="type" value="product">
<input type="search" name="q" class="text" placeholder="{{ 'general.search.placeholder' | t }}" value="{{ search.terms }}">
<input type="hidden" class="btn" value="Search">
</form>
Which returns an array of objects search.results it is not possible to remove elements from that array in Liquid (ex. remove products which has a price of 0)
I want to remove elements from that array because even though i can filter those elements and choose them to show in the page or not, i cant effect {% paginate %} function because it is paginating the unfiltered version of search.results for example {% paginate search.results by 12 %}.
So my question is can i send an advanced query from the very start and only get the result for ex. products which have not a price of 0 ?
Thanks in advance.
I googled about this a lot but couldn't find a solution.
`
Nope you can't. Price is not a valid field in Shopify's search fields - https://help.shopify.com/manual/sell-online/online-store/storefront-search
Alternatively you can tag the products with 0 price and add "-tag" as a field to exclude those items. Refer to the link for detailed description on search on Shopify.

Resources