I'm learning Python with the tutorial app from Flask and I can't figure how to reference a certain row in the database. I m trying to delete a record by using the delete link in the template.I spent a whole day trying everything I could find and to really understand this. I know it's simple but I don't get it!
Here's the html template:
<ul class=entries>
{% for entry in entries %}
<li><h2>{{ entry.title }}
<h2>{{ entry.text|safe }}</h2>
{% if session.logged_in %}
Delete
{% endif %}
{% else %}
{% endfor %}
</ul>
As you can see, next to each entry there's a delete link.How am I supposed to reference the
right id in the database?
Here's the Python function I have so far:
#app.route('/delete')
def delete_entry():
if not session.get('logged_in'):
abort(401)
g.db.execute('delete from entries where id=(select max(id)from entries)')
g.db.commit()
flash('The entry was deleted')
return redirect(url_for('show_entries'))
What I have so far works but It's not what I want. Thanks in advance!
Sebastien the delete_entry function is deleting the last entry in the db
where id=(select max(id)from entries)
What you have to do is insert a parameter in the url for deletion like '/delete/:id' where the id is the id of the entry you want deleted, then change the template to generate the url as so:
Delete
And also change the db query that deletes the entry:
g.db.execute('delete from entries where id=' + id)
Edit1:
I checked the Flask documentation, in order to get variables into your routes you have to modify the route as follows:
#app.route('/delete/<int:entry_id>')
In this way you obtain the entry_id in your python function:
def delete_entry(entry_id):
g.db.execute('delete from entries where id=' + entry_id)
And finally you have to specify your entry id in the url_for function:
Delete
Related
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.
I've added a user profile page to my flask app. Everything is working except for one item:
I would like to display is the user's "Account created on" date. As I've added this functionality (and the logic to record a user's creation date upon registering) after some users have already been created, this column in certain user's tables will be empty.
I decided to work around this with a little humor by using a jinja2 if / else statement to check if the user has a user_created date or not.
If the user has a date, it will be displayed. If not, instead of a date it will replace it with 'since the dawn of time'.
The problem is my {% if user.user_created %} conditional logic seems to be pulling the sqlalchemy DateTime class type instead of None displaying as so:
Member since: <class 'sqlalchemy.sql.sqltypes.DateTime'>
If used this same pattern to check for the existence of other data without problems so I'm guessing it's related to this column containing db.Column(db.DateTime), but I'm not sure how to solve it.
Here is my Jinja template code:
<h1>User: {{ user.username }}</h1>
{% if user.about_me %}<p>{{ user.about_me }}</p>{% endif %}
{% if user.user_created %}
<p>Member since: {{ user.user_created }}</p>
{% else %}
<p>Member since: The dawn of time</p>
{% endif %}
And here is the column from my sqlalchemy User model:
user_created = (db.DateTime)
Any help would be appreciated
Yep, after testing the realization in the comment above, that was in fact the issue.
I accidentally omitted the db.Column in my model. All is working now.
EDITED. My original question wasn't clear enough. I want to allow a user to pass values into a TextField in wtforms, then the value they entered appears after they add it. This would allow the user to pass multiple values before then hitting a final "Sumbit" button on all the values that were originally entered.
I found this question for doing something with the entered text, which is what I tried.
My Python code:
from flask import Flask, request, render_template, redirect
from wtforms import TextField, Form, SubmitField
def redirect_url(default='index'):
return request.args.get('next') or \
request.referrer or \
url_for(default)
class RegionForm(Form):
field = TextField('Region')
Submit = SubmitField('AddRegion')
fieldList = []
def main():
app = Flask(__name__)
#app.route('/region/', methods=['GET'])
def region():
form = RegionForm(request.form)
return render_template("region.html",
form=form)
#app.route('/add/', methods=['POST'])
def add():
request.form['fieldList'].append(request.form['field'])
return redirect(redirect_url())
app.run(debug=True)
My html code:
<form action="/add/" method="Post">
{% for field in form %}
<tr>
<th>{{ field.label }}</th>
<td>{{ field }}</td>
</tr>
{% endfor %}
</form>
{% for item in form.fieldList %}
{{ item }}
{% endfor %}
But after I enter the text and click the "AddRegion" button, I get the following error: The browser (or proxy) sent a request that this server could not understand. However, if I comment out the line request.form['fieldList'].append(request.form['field']), then the redirect happens, but the text hasn't been added to the hidden list on the form. How do I both add the text to the list and redirect back to the original page, so the user can add more text? It seems like there must be an error with this line only, because the rest works fine.
How can I allow a user to dynamically add text to a field, then have that field display in the browser?
Then once the complete region fields have been added, I want to be able to retrieve that list to process in a separate function later.
Part One
So after looking at your code, I think I have found your problem. Flask is very particular about its app routes.
The app route that you have in your flask is:
#app.route('/add', methods=['POST'])
However, your current action on your form which is:
<form action="/add/" method="Post">
In flask /add and /add/ are actually two different web-routes. Therefore, the #app.route is not being triggered. If you change your code to:
`<form action="/add" method="post">`
You should be good to go from here.
Part Two
I think I may have an additional issue. So within your HTML right now, you actually close your </form> tag before looping through your items in the fieldList.
</form>
{% for item in form.fieldList %}
{{ item }}
{% endfor %}
Try:
{% for item in form.fieldList %}
{{ item }}
{% endfor %}
</form>
What I believe to be happening is that your form inputs are not actually being placed inside of the form so when you try to access them you are getting a KeyError.
I second what Cody Myers said. However there's a simple way to guarantee correct routes even if you later change them: in your form use action="{{ url_for('region') }}" and Flask will automatically substitute the correct route for the given function name.
I'm new with Django and i'm trying to show some data from my db but with no luck.
The DB connection is OK and i did syncdb.
I'm trying to iterate on one column of my database (logging) table (handleName)
Model:
class Handle(models.Model):
handleName = models.CharField(db_column='handleName', max_length=200)
def __unicode__(self): # Python 3: def __str__(self):
return self.handleName
View:
def logger(request):
#query_results = Handle.objects.all()
#return render(request, 'ate_logger/logger.html')
query_results = Handle.objects.all()
t = loader.get_template('ate_logger/logger.html')
c = Context({
'query_results': query_results,
})
return HttpResponse(t.render(c))
Html template:
{% if query_results %}
<ul>
{% for handle in query_results %}
<li> name {{ handle.handleName }} </li>
{% endfor %}
</ul>
{% else %}
<p>No data available</p>
{% endif %}
The problem is that i'm getting No data available but i know for sure i have the data in the db. I've tried to use the tutorial but every thing i do seems OK so maybe someone can suggest a solution?
EDIT-1
I'll try to add some mote information i have a data base with data made by another software, i want to connect with Django to that database and show it's content.
as first step i'm trying to iterate on table Handle column idHandle and to show all the values.
the problem is that i have no return values in return self.handleName
I have tried it also in the manage.py shell and it's also empty.
Problem is solved by #yuvi help!
Auto modeling the db was the needed option.
docs.djangoproject.com/en/dev/howto/legacy-databases
Previously I had a client summary list in a table. In one column I had a list of object types and in another, I had the quantity of that object type.
#login_required
def client_summary(request, client_id):
client = models.Client.objects.get(pk = client_id)
items = client.storageitem_set.all()
tape_and_film_items = client.storageitem_set.filter(type="1")
total_tape_and_film_items = tape_and_film_items.count()
electrical_equipment_items = client.storageitem_set.filter(type="2")
total_electrical_equipment_items = electrical_equipment_items.count()
storage_office_equipment_items = client.storageitem_set.filter(type="3")
total_storage_office_equipment_items = storage_office_equipment_items.count()
<table cellspacing="15" style="float: left">
<tr><th scope="col">Type</th><th scope="col">Quantity</th></tr>
</tr><td>Tape + Film</td><td align="center">{{total_tape_and_film_items}}</td></tr>
</tr><td>Electrical Equipment</td><td align="center">{{total_electrical_equipment_items}}</td></tr>
</tr><td>Storage Office Equipment</td><td align="center">{{total_storage_office_equipment_items}}</td></tr>
</table>
Now this would work, but there is a problem. I did not knew earlier that users could add their own storage object from a form in my web app. If they try add a new object type, it will not show up in my client summary unless I explicitly write up an django query in a view passing a variable in a template. If there was no form to add an object type, this would have worked.
So in my template now I have this now in the type column. This part will work because all I really need to do is list all the storage item objects regardless of whoever client it is.
views.py
item_type = models.StorageObject.objects.all()
template
{% for item in item_type %}
{{item.title}}
{% endfor %}
But in the quantity column I can't seem to count. Returns nothing.
{% for item in items %}
{{item.type.count}}
{% endfor %}
If you need to display some info of items for every tag, you can use regroup tag. If you want only quantity, use Count aggregation function.