Flask grid edit using wtforms - python-3.x

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)

Related

How do I Correctly Render Python Data in Jinja HTML Templates?

I'm extremely new to python/flask, so I don't have the capacity to describe what I'm doing wrong. Please be patient with me.
As I'm in the learning stages, my goal is to create a simple app with GET, PUT, POST, DELETE functionalities. I'm using flask to render a template for a project; I'm using forms to make an HTML page. The one key issue here is:
in my routes.py
#app.route("/")
#app.route("/home")
def home():
all_pokemon = Pokémon.query.all()
result = ""
for pokemon in all_pokemon:
result += f"{pokemon.id} | {pokemon.pkname} | {pokemon.nickname}<br>"
return result
This, gives me what I want, which is this:
However, I have an home.html setup to do exactly the same thing. Simply show me this information.
in my home.html
{% extends 'layout.html' %}
{% block body %}
<h1>version 1.0.0</h1>
<br>
{% for pokemon in all_pokemon %}
{{ "{pokemon.id} | {pokemon.pkname} | {pokemon.nickname}" }}
<br>
{% endfor %}
{% endblock body %}
and to get that working, i have this in my routes.py
#app.route("/")
#app.route("/home")
def home():
all_pokemon = Pokémon.query.all()
return render_template("home.html", all_pokemon=all_pokemon)
But, doing this, gives me this output:
My question is, how do I get the render_template to NOT display the incorrect output, and to properly display the correct output of my forms?
I've been searching for an answer for this issue without an understanding of the proper terminology and have consequently made no progress for the past 3.5 hours. Any help is greatly appreciated. Swift help is incredibly appreciated.
Thank you. If I need to post more information please let me know.
I've figured it out, and as I suspected it was embarassingly simple.
The render template worked, but where I had
in my home.html
{{ "{pokemon.id} | {pokemon.pkname} | {pokemon.nickname}" }}
I should have had
{{ pokemon.id }} | {{ pokemon.pkname }} | {{ pokemon.nickname }}
I apologise for anybody who may have wasted their time searching for an answer, and I hope this can serve as a helpful guide to any other newbies like myself who get stuck on this.
Hopefully 7 years from now I can look back on this moment affectionately and laugh about it.
{% for pokemon in all_pokemon %}
{{ "{pokemon.id} | {pokemon.pkname} | {pokemon.nickname}" }}
<br>
{% endfor %}
Firstly you should use your context like that:
{{pokemon.id}} | {{pokemon.pkname}} | {{pokemon.nickname}}
And if you want to render your context, your view should be like that:
#app.route("/home")
def home():
all_pokemon = Pokémon.query.all()
result = ""
for pokemon in all_pokemon:
result += f"{pokemon.id} | {pokemon.pkname} | {pokemon.nickname}<br>"
if all_pokemon is not None:
return render_template("home.html", all_pokemon=all_pokemon, result=result)
else:
return render_template("home.html",all_pokemon=all_pokemon, result = "")
If you use your context named result, you should use a control in your template folder like that:
.html
{% if result|length > 1 %}
...
{% endif %}

Concatenate in an element acf fields or an objects

I'm trying to concatenate a Twig variable and an ACF options field but it doesn't work.
I have two footers and I want to select the correct one according to the correct page.
{% if post.slug == "page1" %}
{% set pageType = "pages" %}
{% elseif post.slug == "page2" %}
{% set pageType = "otherspages" %}
{% endif %}
<footer id="footer">
<h2>{{ options.footer_~pageType~_titre }}</h2>
<div>{{ options.footer_~pageType~_container }}<div>
</div>
The ACF fields are called footer_page_titre or footer_otherpage_titre depending on the footer I want to display
Thank you
Try constructing the field name first, for example with the twig format filter which formats a given string by replacing the placeholders, similar to sprintf, and then access the field value by in the options data array.
Construct the field name:
{% set footer_title = "footer_%s_title"|format(pageType) %}
Access the value by array key
<h2>{{ options[footer_title] }}</h2>

INDEX only pulling one row of data from database

For the life of me I cannot get my index page to properly display the data from my database. I have tried multiple methods and research on several sites. I'm thinking it is something right in front of my face, but right now I can't see the forest through the trees. I have included my code below.
Application:
#app.route("/")
#login_required
def index():
users = db.execute("SELECT * FROM users WHERE id = :user_id", user_id=session["user_id"])
stocks = db.execute("SELECT * FROM transactions WHERE id = :user_id", user_id=session["user_id"])
quotes = {}
for symbol in stocks:
quotes[symbol["symbol"]] = lookup(symbol["symbol"])
return render_template ("index.html", quotes=quotes,stocks=stocks, symbol=symbol)
index.html:
{% extends "layout.html" %}
{% block title %}
Portfolio
{% endblock %}
{% block main %}
<table class="table table-striped">
<tr>
<th> Symbol</th>
<th> Current Share Price</th>
<th> Shares Owned</th>
<th> Shares Owned Value</th>
</tr>
{% for stock in stocks %}
<tr>
<td>{{symbol.symbol}}</td>
<td>{{quotes[stock.symbol]["price"] | usd }}</td>
<td>{{symbol.shares}}</td>
<td>{{symbol.total_price}}</td>
</tr>
{% endfor %}
</table>
{% endblock %}
Finally here is a screenshot of my index.html as it generates now:
And the data in my database table:
As you can see, the table displays the symbol, shares and total price from only one of the transactions. It shows the correct updated price for each stock, but I can't get it to pull the correct data from the table. Thank you so much for any help.
symbol has the value of the last iteration of for symbol in stocks:. Looks like the html should be creating the td elements from stock ({% for stock in stocks %}) not from symbol.
Suggestion to simplify:
In the for symbol in stocks: loop in the .py, add a key to the symbol dictionary for price. That would render the quotes object unnecessary and the stocks list would be self contained.

HuBL: How to check what lists a contact is part of by contact ID?

I'm trying to show specific content if a user is part of a list in HubSpot.
Psuedo:
If contact_id is part_of_this_list then do this
The contact ID at the moment is being obtained from the query string. I'm trying to check if the user is part of said list, but it's not working.
Approach:
{% set id_querystring = request.query_dict.id %}
{% set registration_list_id = "6136" %} <!-- id of the list I'm checking -->
{% if id_querystring in registration_list_id %}
contact is part of list
{% else %}
contact is not part of list
{% endif %}
i use this code:
{% set list_variable = request_contact.list_memberships|pprint %}
{% if "id of the list you are checking" in list_variable %} ← without the quotes
yes, you are in the list
{%else%}
No, you are not in the list
{%endif%}

Craft CMS access image from a different entry using ID

Hi how do I access an image from a different entry / page /url? I'm building in Craft CMS.
I'm creating a nav that will be used across the site. It works fine and I can pull the title and page url ok. I want to use a picture from that page as a thumbnail for the link but it doesn't work.
On my page I have 4 or 5 featured images but I just want to access the first one. What ever I try doesn't work
{% set image = craft.entries.id(50 ####this is the page ID that the image is attached to).featuredImages %} - doesn't work.
Basically how do I access an image when all I have is the id number of the page it is attached on?
Any help would be much apreciated,
Thanks.
Phew, found it. Perhaps there's a cleaner way but:
{% set pageData = entry.id(50) %} ## or in my case swap 50 with node.entryId as I'm using Navee plugin to build my nav.
{% set x = 1 %}
{% for image in pageData.featuredImages %}
{% if x == 1 %}
<img class="navImage" src="{{ image.getUrl('siteThumb') }}" alt="{{ page.title }}">
{% set x = 2 %}
{% endif %}
{% endfor %}

Resources