Flask: Make Application State Persist over tabs - python

I'm new to Flask and am trying to create an application that can remotely control a voltage supply to set voltage/current and turn the voltage supply on and off on and off. With these actions, I would like to update some info on the webpage.
The issue I'm running into is, if, for example, I set the power/current, I see the stats show up on the web page in the current table I'm in. But if I copy the same URL into another tab, I do not see the stats. Is there a way to show the stats on all web pages?
Below is a snippet from my server.py. I think it has something to do with the return values and what I'm rendering upon return, but I'm not sure now to fix this.
#application.route('/set-power-current', methods=["GET", "POST"])
def set_power_current():
if request.method == "POST":
req = request.form
ip = req["ip"]
serial = req["serial"]
power = req["power"]
current = req["current"]
channel = req["channel"]
set_power_current_channel(ip, serial, power, current, channel)
feedback = {"Power": power,
"Current":current,
"Channel":channel
}
if int(channel) == 1:
return render_template('index_server.html', data1=feedback)
if int(channel) == 2:
return render_template('index_server.html', data2=feedback)
if int(channel) == 3:
return render_template('index_server.html', data3=feedback)
return redirect(request.url)
return render_template('index_server.html')
Here is a snippet from my index_server.html to post the stats
<h2>Channel Stats</h2>
<div class="row">
<div class="column" style="background-color:#aaa;">
<h2>Channel 1</h2>
<ul>
{% if data1 %}
<li>Power: {{data1.Power}}</li>
<li>Current: {{data1.Current}}</li>
{% endif %}
</ul>
</div>
<div class="column" style="background-color:#bbb;">
<h2>Channel 2</h2>
<ul>
{% if data2 %}
<li>Power: {{data2.Power}}</li>
<li>Current: {{data2.Current}}</li>
{% endif %}
</ul>
</div>
<div class="column" style="background-color:#ccc;">
<h2>Channel 3</h2>
<ul>
{% if data3 %}
<li>Power: {{data3.Power}}</li>
<li>Current: {{data3.Current}}</li>
{% endif %}
</ul>
</div>
</div>
Here is what the current tab looks like after setting the values in Channel 3, for example:
Here is what a new tab looks like after I set the values:
I would like to find a way for both tabs to look the same after values are set.
Thanks!

If you want the stats to show on multiple pages, you should store them and not only display them.
You can easily make use of a database like SQLAlchemy to store the statistics and retrieve them after. It will then be consistent across all tabs/ pages.

Related

Flask with sqlalchemy how can i highlight my searched query results?

I am making my app in which I'm querying my data base with like search and what I wanna do is to highlight the results which are showing in my result template. My search route looks like this:
#app.route("/post")
def post():
term = request.args.get("search_text", None)
if term == None:
scanned = Images.query.filter_by().all()[0:15]
return render_template('post.html', scanned=scanned)
else:
term = request.args.get("search_text")
search = "%{}%".format(term)
scanned = Images.query.filter(or_(Images.content.like(search),Images.title.like(search)))
return render_template('post.html', scanned=scanned)
this my template file post.html
{% for scanned in scanned %}
<div class="post-preview">
<a href="/post2/{{scanned.Slug}}">
<h2 class="post-title">{{ scanned.title }}
</h2>
</a>
<p class="Images-meta">Posted by
Admin
on {{scanned.Date}}</p>
</div>
{{scanned.content[0:120]}}...
<hr>
</li></a>
{% endfor %}
now everything is working fine but I just want to highlight my search query in results template.
You write the template 'post.html'. You need to modify that html file to change how things are displayed.

For loop using Jinja and PyMongo repeating the same output for an entire dict

I am trying to print who a friend request has come from. To do so I have this app.route:
#app.route("/friend_requests", methods=["GET", "POST"])
def friend_requests():
user = session["user"] or None
find_request = mongo.db.friend_requests.find_one({"friend_request_to": user})
print(find_request)
return render_template("friend_requests.html", find_request=find_request)
I am then adding this to a for loop in HTML using Jinja:
{% for find_requests in find_request %}
<span>from {{ find_request.friend_request_from }}</span>
{% endfor %}
The print(find_request) output in the terminal is this:
{'_id': ObjectId('600d281ec3957da9d448b845'), 'friend_request_from': 'admin2', 'friend_request_to': 'test3'}
And the output into the HTML (I will flash it up later when I get this right) is this:
from admin2 from admin2 from admin2
The loop seems to repeat for every item in the collection.
What I really want is the loop to find every time a user friend request is sent to this logged in user. In this case, for testing purposes, only one request has been sent.
How do I get the loop to print just the friend_request_from item in the collection?
I decided to beef up the route:
#app.route("/friend_requests/<user>", methods=["GET", "POST"])
def friend_requests(user):
user = session["user"]
find_request = mongo.db.friend_requests.find({"friend_request_to": user})
print(user)
print(find_request)
return render_template("friend_requests.html", find_request=find_request)
Part of the problem was the variable naming - I was confusing myself.
{% for x in find_request %}
<li>
<div class="collapsible-header teal lighten-5">
<i class="fas fa-chevron-circle-down blue-text text-darken-3"></i>
<strong>{{ x.friend_request_from }}</strong>
</div>
</li>
{% endfor %}
(slightly styled, but the loop remains the same).
This solves for the entire output.

Returning a list using flask and SQLite

I was wondering how I could return individual values from an SQLite table into a list using flask. At the moment the result is showing all three available values from the table but I want them to be listed individually (green text). Below I print the values in the code to show you what I would like reflected on the webpage. The end goal is for each to be a link to the respective ad. Frankly I am pretty new and am stuck so any direction would be super helpful on what the next steps should be here. The links to the respective ads will be done with dynamic URLs which I believe I know how to do. Right now, I just want to know if I could get the values from the flask template.
app.py
#app.route("/my_ads")
#login_required
def my_ads():
conn = sqlite3.connect('food.db')
conn.row_factory = lambda cursor, row: row[0]
c = conn.cursor()
ads = c.execute("SELECT image_key FROM food").fetchall()
for row in ads:
print(row)
return render_template("my_ads.html", ads=ads
my_ads.html
{% extends "layout.html" %}
{% block main %}
...
<div class="row">
<div class="column">
<h2>My Ads</h2>
<ul>
{% for ad in ads %}
<li>{{ads}}</li>
{% endfor %}
</ul>
</div>
{% endblock %}
In your <ul>'s for loop, instead of using <li>{{ads}}</li>, use just <li>{{ad}}</li> to access the individual values.

Pagination when search and results are on the same page

I have a template where the users pass a query and select a couple of checkboxes (these can range from 1-100). Then, my view does the following:
def search(request):
results_list = search(request.GET.get("q", ""), request.GET.getlist("c"))
# Pagination
paginator = Paginator(results_list, 10)
page = request.GET.get("page")
results = paginator.get_page(page)
return render(
request,
"web/search/show.html",
{
"query": query,
"results": results,
},
)
The issue arrises because both the search and the presentation of the results happen on the same page. Therefore, when I want to include pagination, in my template, I have to do the following:
<div class="pagination">
<div class="step-links">
{% if results.has_previous %}
Previous
{% endif %}
{% if results %}
<span class="current">
Page {{ results.number }} of {{ results.paginator.num_pages }}
</span>
{% endif %}
{% if results.has_next %}
Next
{% endif %}
</div>
</div>
Please consider the usage of request.GET.urlencode because when the user wants to either go to the previous or next page the same query and checkboxes need to be passed. However, this creates a bug when the user goes past the second page, because the ?page=3&page=2 keep on piling up. Can someone point me in the right direction for solving this issue?
An easy solution would be to repeat every GET parameter you need to handle in the link rather than use the full querystring, something like:
Next
A more elegant solution would be to create a Django template tag to build the URL based on the current state of the querystring, something like what is described in this article: Dealing With QueryString Parameters.

How to access variables within html template url_for

I'm building a Netflix like website for my Devops course. I made a Python list of dictionaries (Mockfilms) to define my films, and want to populate a database (Ratings) with reviews in preparation for sending data in the format :filmid: :userid: :rating: to a recommendation engine.
My index page is a list of film images with a link to a review form under each one. I want each review form to appear on a different url (/review/ID where ID is saved in mockfilms as oid). In order to do this I want to access mockfilms.oid, then pass it to the view function to make the url for the form. Once the form is complete I then want to add this ID to the Ratings database. Here is what I have so far:
Index:
{% extends "base.html" %}
{% block content %}
<h1>Hello, {{ current_user.username }}! Welcome to our extensive video library:</h1>
{% for film in mockfilms %}
{% set ID = film.oid %}
<div>
<a href = {{ film.video }}>
<img src = {{ film.image }} alt = "doh" style = "width:200px;height:200px;border:0;">
</a>
</div>
<div>
">Leave a review here!
{% endfor %}
{% endblock %}
Route:
#app.route('/review/<ID>', methods = ['GET', 'POST'])
#login_required
def review(ID):
form = ReviewForm()
if form.validate_on_submit():
review = Ratings(User_id = current_user.id, Score_given = form.score.data, Film_id = ID)
db.session.add(review)
db.session.commit()
flash('Thanks for your review')
return redirect(url_for('index'))
return render_template('review.html', title='Review Page', form=form)
The following error is what I get when I run it:
File "/home/jc/Desktop/Lokal/DevopsAssig/microblog/Kilfinnan/lib/python3.5/site-packages/werkzeug/routing.py", line 1768, in build
raise BuildError(endpoint, values, method, self)
werkzeug.routing.BuildError: Could not build url for endpoint 'review'. Did you forget to specify values ['ID']?
From this I assume that the issue is with the ID variable within this template. My searchings and learnings led me to believe that {% set %} in the index template would let me declare the ID variable and then use it in the dynamic.
Try this:
{% block content %}
<h1>
Hello, {{ current_user.username }}!
Welcome to our extensive video library:
</h1>
{% for film in mockfilms %}
<div>
<a href="{{ film.video }}">
<img src="{{ film.image }}" alt="doh" style="width:200px;height:200px;border:0;" />
</a>
</div>
<div>
<a href="{{ url_for('review', ID=film.oid) }}">
Leave a review here!
</a>
</div>
{% endfor %}
{% endblock %}
Ultimately your solution was quite close, but it is not necessary to use the Jinja set command when you need to pass the variable into url_for() function using the keyword for the parameter. You could still do it using {% set ID = film.oid %} but it would be a bit superfluous.
Try to provide key=value arguments into your url_for function.
Something like this
">Leave a review here!
Also Flask have a great documentation, Flask docs

Categories

Resources