passing variable to a table in flask - python

I am following this video and everything is working perfectly. The output of a SQL query is saved within a variable that I can call on in another .html page.
so my sql query is:
#app.route('/all_data')
def all_data():
customers = db.get_customers()
for customer in customers:
var = customers
return render_template('all_data.html',var=var)
When calling this {{var}} in all_data.html page the output is for a long tuple:
('name','email','comment','gender'),('name','email','comment','gender') etc etc
I am looking to put this {{var}} into a table instead?.. I but am hitting a brick wall in finding out how to do this?
any help would be much appreciated!

Assuming you're using Flask's default template engine (Jinja2), you can simple use a for loop to iterate over the elements of the collection inside the template. The syntax is:
{% for item in items %}
{{ item }}
{% endfor %}
So simply create an HTML table, and add a row for each item in your var variable.
IIRC, Jinja tuples act the same as Python's, so you can probably do something along the lines of:
<table>
<thead>
<tr>
<th>Name</th>
<th>Email</th>
<th>Comment</th>
<th>Gender</th>
</tr>
</thead>
<tbody>
{% for current in var %}
<tr>
<td>{{ current[0] }}</td>
<td>{{ current[1] }}</td>
<td>{{ current[2] }}</td>
<td>{{ current[3] }}</td>
</tr>
{% endfor %}
</tbody>
</table>
I haven't checked it (as I don't have a Flask project available right now), but if my memory serves me right, that's how I would do it
Here's a link to an usefull part of Jinja2's documentation
Also, what is this piece of code for ?
for customer in customers:
var = customers
You're iterating over each element of the list, but your never use the customer variable (containing the current element). Instead, you assign the var variable to the customers list multiple times. Assuming customers is a simple Python list, you could remove this loop and simply do return render_template('all_data.html',var=customers)

Related

Using django-auditlog, how can I display the 'actor_id' for a particular model?

I have created a simple Django application to display individual articles. These articles have a number of fields that users can edit. I am using the package 'django-auditlog' to log changes to these article models. So far, I have simply followed the auditlog installation doc to setup model history tracking (as well as enabling the middleware to allow 'actor_id' to be tracked). I have also added the example code that displays the most recent changes on the individual model pages as such:
<!-- History display -->
<div class="table-responsive">
<table id="history" class="table table-striped table-bordered">
<thead>
<tr>
<th>Actor</th>
<th>Field</th>
<th>From</th>
<th>To</th>
</tr>
</thead>
<tbody>
<!-- Human readable - change to '.changes_dict.' for proper logs -->
{% for key, value in article.history.latest.changes_display_dict.items %}
<tr>
<td>{{ article.history.latest.author_id }}</td>
<td>{{ key }}</td>
<td>{{ value.0|default:"None"|striptags|safe }}</td>
<td>{{ value.1|default:"None"|striptags|safe }}</td>
</tr>
{% empty %}
<p>No history for this item has been logged yet.</p>
{% endfor %}
</tbody>
</table>
</div>
As my code may suggest, I am trying to add an additional column to the history table to show who made the changes that are being displayed.
Is there an easy way to do this through auditlog, or will I have to create some kind of sql query to my sqlite auditlog db table to retrieve the 'author_id' field?
Thank you!
I figured out the answer after looking through the models file for Django AuditLog. It is not possible to pull the actor out directly from the history field of the model if you have created the history field using the AuditlogHistoryField() method as described in the django-auditlog tutorial.
Instead, I did the following:
In the views.py file
from auditlog.models import LogEntry
...
dal_log = LogEntry.objects.get_for_object(article)
...
context = {'article': article, 'logs': dal_log}
return render(request, "detail.html", context)
Then in my template, I was able to work with the log entries for the specified object (in my case, these were 'article' models). There may be a cleaner way, but this worked for me.

How do I use Flask's url_for in a template?

I am building a Flask application to manage character sheets for an RPG using an SQL database.
Currently, I have the following script that displays the list of a user's characters currently in the database.
#app.route("/<cha_name>")
#login_required
def character_sheet():
characters = db.execute(
"""SELECT
*
FROM
characters
WHERE
user_id = :user_id AND
name = :cha_name
""",
user_id=session["user_id"],
cha_name="???",
)
if not characters:
return render_template("add_char.html")
I would like to include a button that navigates to the character sheet for the specic chosen character. So the page below would detail some of the stats for the character, and then a button would take the user to a populated character sheet on another page.
This is what I have so far for displaying a specific user's characters.
{% extends "main.html" %}
{% block title %}
Characters
{% endblock %}
{% block main %}
<table border = 1>
<thead>
<td>Player</td>
<td>Name</td>
<td>Race</td>
<td>Class</td>
<td>Level</td>
<td>Status</td>
<td>View</td>
</thead>
{% for row in rows %}
<tr>
<td>{{ character["user"] }}</td>
<td>{{ character["name"] }}</td>
<td>{{ character["race"] }}</td>
<td>{{ character["cha_class"] }}</td>
<td>{{ character["level"] }}</td>
<td>{{ character["status"] }}</td>
<td><a href={{ url_for('cha_name') }}>View Sheet</a></td> <!-- HERE -->
</tr>
{% endfor %}
</table>
Add a new Character
Go back to home page
</body>
{% endblock %}
What do I use on the line with <!-- HERE --> to make a link to the character sheet URL?
Whew, there's a lot to unpack here!
Your example is/was invalid, e.g. cha_name= on the end of the db.execute() call, and there are no calls to render_template if a character is found, so it'll never produce a response even with a valid request.
Next, you've told Flask to pass a cha_name parameter to your character_sheet function, but haven't defined a parameter on the function itself.
Finally, in your template you're passing cha_name to the url_for function, which (so far as we can see from the sample code) isn't a route that you've defined, so can't work.
You need to include more information for us to help, such as telling us what error you're seeing. Right now, I imagine the Flask service won't even start due to the syntax error. Once that's fixed, I'd expect to see something like the following:
werkzeug.routing.BuildError: Could not build url for endpoint 'cha_name'. Did you mean 'character_sheet' instead?
I'd suggest you head back to the documentation on URL building and also look at the docs for the route decorator. You'll see on the latter that "Flask itself assumes the name of the view function as endpoint". That means that in order to get Flask to generate a URL for your character_sheet function, you'll need to pass that name to url_for, and then the parameters, like this:
url_for('character_sheet', cha_name=character.name)
If a user were to rename their character, all of the URLs would change, which is a bad user experience — what would happen if they'd bookmarked a particular character, then fixed a typo in the name?
Putting this all together, here's a hopefully-better example:
# app.py
#login_required
#app.route("/<character_id>")
def character_sheet(character_id):
characters = db.execute(
"""SELECT
*
FROM
characters
WHERE
id = :id AND
user_id = :user_id
""",
id=character_id,
user_id=session["user_id"],
)
if not characters:
return abort(404)
return render_template(
"characters/sheet.html",
character=characters[0],
)
<!-- templates/characters/list.html -->
{% extends "main.html" %}
{% block title %}
Characters
{% endblock %}
{% block main %}
<table>
{% for character in characters %}
<tr>
<td>{{ character.name }}</td>
<td><a href={{ url_for('character_sheet', character_id=character.id) }}>View Sheet</a></td>
</tr>
{% endfor %}
</table>
Add a new Character
{% endblock %}

Django: Accessing list attributes in template

I have a SQL query in a Django view and store the results in a variable. As far I know the result should be stored as a list.
def assignments(request):
cursor = connection.cursor()
cursor.execute("SELECT o.article_id, o.amount, m.id, o.create_date, m.status FROM orders o, producers p, machines ma, matches m WHERE ma.producer_id=1 AND m.machine_id = ma.id AND m.order_id = o.id")
articles = cursor.fetchall()
context = {"article_list": articles}
return render(request, 'assignments.html', context)
Then I want to transfer that data row by row in a table in my template.
{% block body %}
<div class="container">
<table class="table">
<thead>...</thead>
<tbody>
{% for articles in article_list %}
<tr>
<td>{{ articles.article_id }}</td>
<td>{{ articles.amount }}</td>
<td>{{ articles.id}}</td>
<td>{{ articles.create_date }}</td>
<td>{{ articles.status }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endblock %}
Unfortunately the table is empty and is not showing any results.
The query itself should be fine. I tested the query in my database workbench and it is showing the correct results.
How can I access the data stored in variable articles from my template?
PS: I'm far from being a programmer. So I don't really know any programming concepts/language.
Any help is highly appreciated. Thanks!
You have a list of lists. Each element in articles_list is just a list of values from the database; it does not have any knowledge of attributes like "id" or "amount".
As Arpit says in the comments, you should be using Django models for this rather than raw SQL.

Unicode issues when requesting form

I'm using HTML, Flask and MYSQL to populate a table when the user first loads the page. The table displays all the rows along with a checkbox and when a user presses the submit button, I get the rows that were checked.
Current HTML code
{% for row in data %}
<tr>
<td><input type="checkbox" name="inputSelect" value="{{ row[0], row[3] }}"></td>
<td>{{ row[0] }}</td>
<td>{{ row[1] }}</td>
<td>{{ row[2] }}</td>
<td>{{ row[3] }}</td>
</tr>
{% endfor %}
However, when I try request.form['InputSelect'] on the flask side, it only gives me one result even if I click more than one checkbox.
What's the best way to create the table so that when I click multiple checkboxes, I can see all of them using request.form['InputSelect']
Flask use MultiDict. To get the list of items for a given key, you can use getlist() method.
Try this:
value = request.form.getlist('InputSelect')

Using jinja to generate a CSV file

I'm not quite sure if Jinja is the right tool for the job, but seeing as it's used elsewhere in our environment I thought I'd try and use this as an exercise to familiarise myself with it.
I have a list a = [1, 2, 3, 4, 5, 6, 7, 8, 9]
I need to write the values in it to create a CSV file. All values in the CSV file will be fixed except for the values in a.
So I imagine a template file will look something like this (I know this is not Jinja2 syntax):
a[0], 'something',
a[1], 'else',
a[2], 'but',
.
.
a[5], 'repeated statement',
a[6], 'repeated statement',
.
a[8], 'here endeth the lesson',
Can I access the elements in 'a' by index like I would in Python and create my output file?
I'm not sure what exactly your end goal is, but jinja is more of a templating tool for generating views, rather than some kind of file. Like what #Marat said, you could use the csv module to create a csv file.
However, if your real purpose is to use jinja to create some type of table view where the values in your list are populated in the table, then you can certainly do that in jinja.
In your HTML view, you would do something like this:
<table>
<thead>
<tr>
<th>List[idx]</th>
<th>Value</th>
</tr>
<thead>
<tbody>
{%- for item in a -%}
<tr>
<td>a[{{ loop.index - 1 }}]</td>
<td>{{ item }}</td>
</tr>
{%- endfor -%}
</tbody>
</table>
Of course, you have to pass your a list as a context variable to your jinja in order for this to work. I'm assuming you're using Flask as your framework:
#app.route('/your-route')
def your_route_function():
... # your code for creating the 'a' list
... # more code
return render_template('yourhtml.html', a=a)
Now, if you want to access your list by index, that's possible too. You would have to determine the length of your list though using jinja's length filter:
<table>
<thead>
<tr>
<th>List[idx]</th>
<th>Value</th>
</tr>
<thead>
<tbody>
{%- for idx in range(a|length) -%}
<tr>
<td>a[{{ idx }}]</td>
<td>{{ a[idx] }}</td>
</tr>
{%- endfor -%}
</tbody>
</table>

Categories

Resources