I want to pass a value from html link to my function in flask:
the police man name has a button next to it if it is clicked i should take its id and send it to the python function here is the html code :
<ul class="list-group">
{% for p in policemen %}
<li class="list-group-item">{{ " "~ p.rank ~" "}}
<div class="col-md-2 text-center">
<a href='/deletepolice/{{p.id}}' class="btn btn-primary btn-lg" >
</div> Delete ?
</a>
</li>
{% endfor %}
here is the python function :
#app.route('/deletepolice/<string:id>', methods=['GET','POST'])
def deletepolice(id):
# Create cursor
cur = mysql.connection.cursor()
# Execute
cur.execute("DELETE FROM police WHERE id = %s", [id])
# Commit to DB
mysql.connection.commit()
#Close connection
cur.close()
flash('Police man deleted', 'success')
return redirect(url_for('policemen'))
This should work. At the moment though the render_template of your HTML is not shown. Make sure that you are correctly passing the id to your a tag. When clicked the current way you have your a tag setup should lead you to that route.
Are you getting errors when you click the link? If so what are they?
Related
I am trying to display at the bottom of a webpage, a message or a card, like the description of an item when user clicks a submit button
My Python code looks like this:
#app.route("/factpage", methods=["GET","POST"])
def enterfruit():
if request.method == "POST":
fruit = request.form.get("fruitname")
username = session["username"]
db.execute("insert into fruits(username, fruit) values (?,?)", username, fruit);
desc = db.execute("select description from fruitinfo where fruit=?", fruit)
flash("Thank you for entering " + fruit + "!")
return render_template("factpage.html")
# how can I display this description(desc) as a card at the bottom of the page??
else:
return render_template("factpage.html")
I tried to add this in factpage.html, but it is not displaying:
{% block content %}
<div class="container">
<div class="card">
<div class="card-header">
Quote
</div>
<div class="card-body">
<blockquote class="blockquote mb-0">
<p>{{ desc }}</p>
</blockquote>
</div>
</div>
</div>
{% endblock content %}
flash("Thank you for entering " + fruit + "!")
return render_template("factpage.html", desc=desc)
render_template() can take multiple arguments. The first is the html file/string of "static" code you would like to show. Any following keyword arguments are passed to the jinja templating to be used in rendering the final html. In this case, while desc was a variable in your python code it was not available to be used by the jinja templating.
I am building a movie application. I have set up a movie page with brief details about the movie and 2 button: Watched and Saved, which can save into a users watched list or save for later list.
I have set up my backend so that if a user clicks on the watched or saved button more than once, it should not save the movie to the database table watchedmovies or savedmovies. However i am struggling to display an error message that will be displayed to the user.
I am not using forms - so unable to follow the steps to do form validation.
Below is my backend code for the watched route, where I see if the record exists in my database table, if it does i flash or get a message, saying you have already watched this movie. If its not in my database I flash or get message saying it has been saved into your watched list.
cursor.execute( "SELECT * FROM watchedmovies WHERE username LIKE %s", [username_new] )
watched_post = cursor.fetchone()
print(watched_post)
message = ""
if watched_post:
message = "You have already saved this movie to your watched list!"
flash('You have already saved this movie to your watched list!', 'danger')
return redirect(url_for('movie', id=id))
else:
cursor = mysql.connection.cursor(MySQLdb.cursors.DictCursor)
cursor.execute('INSERT INTO watchedmovies VALUES (% s, % s, % s)', (watched_username, id, watched_title))
mysql.connection.commit()
flash('This movie has been saved to your watched list!', 'success')
message = 'This movie has been saved to your watched list!'
return redirect(url_for('user', id=id, username_new=username_new, current_post=curren
t_post, profile_post=profile_post, watched_post=watched_post, message=message))
HTML code snippet of the watched and saved button. I have tried to put the message but it doesnt work
<div class="message">{{ message }}</div>
<a class="btn btn-primary btn-sm mt-1 mb-1" href="{{ url_for('watched', id=current_post.id, username_new=profile_post.username)}}">Watched</a>
<a class="btn btn-primary btn-sm mt-1 mb-1" href="{{ url_for('save', id=current_post.id, username_new=profile_post.username)}}">Saved</a>
You should use get_flashed_messages() function in the jinja template. check the code below, it should work.
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
{% for category, message in messages %}
<div class=" alert alert-{{category}}" role="alert">
{{message}}
</div>
{% endfor %}
{% endif %}
{% endwith %}
Basically I have a for loop to generate N buttons. Each button has a name and an id to recognize the activity. When one of these buttons is clicked, a new HTML page is opened in order to display the info of that activity. I could open the page but I need to pass the value of the button or I won't know which activity was clicked. There must be a pattern to do this.
You can check the code here:
<div class="activities">
<h2>Activities</h2>
{% set i = [0] %}
{% for d in data %}
<button class="btn btn-info" style="margin: 10px;" value="{{ indexs[i[0]] }}">{{ d }}</button>
{% if i.append(i.pop() + 1) %}{% endif %}
{% endfor %}
</div>
#views.route('/activity')
def activity():
return render_template("activity.html")
need to pass the value of the button
Simplest way I can think of is using URL query parameters, simplified example:
HTML snippet:
<div>
<button>first</button>
<button>second</button>
<button>third</button>
</div>
Flask:
from flask import request
...
#views.route('/activity')
def activity():
return "You clicked " + request.args["buttonid"] + "button"
must be a pattern to do this
FORMs (HTML tag <form>) are currently in use for this purpose.
I'm learning flask and I have a little problem.
I made an index template, where are blog post titles.
{% for title in titles %}
<!-- Main Content -->
<div class="container">
<div class="row">
<div class="col-lg-8 col-lg-offset-2 col-md-10 col-md-offset-1">
<div class="post-preview">
<a href="{{ url_for('post')}}">
<h2 class="post-title">
{{ title[0] }}
</h2>
</a>
<p class="post-meta">Posted by {{ author }}</p>
</div>
</div>
</div>
</div>
{% endfor %}
Here is part of my post.html template.
<div class="container">
<div class="row">
<div class="col-lg-8 col-lg-offset-2 col-md-10 col-md-offset-1">
<p>{{ post_text1 | safe }}</p>
<hr>
<div class="alert alert-info" role="alert">Posted by
{{ author }}
</div>
</div>
</div>
</div>
I'm using sqlite3. Currently every title leads to same post.html where is first text from first post.
How to make every title direct to their post text? I mean, if I click on the first title it should bring up post.html and there should be first text. Second title should show second text.
Should I write program, that creates new html for every post or is there any other way?
#app.route('/')
def index():
db = connect_db()
titles = db.execute('select title from entries')
titles = titles.fetchall()
author = db.execute('select author from entries order by id desc')
author = author.fetchone()
return render_template('index.html', titles=titles[:], author=author[0])
#app.route('/post/')
def post():
db = connect_db()
post_text1 = db.execute('select post_text from entries')
post_text1 = post_text1.fetchone()
author = db.execute('select author from entries where id=2')
author = author.fetchone()
return render_template('post.html', post_text1=post_text1[0], author=author[0])
The problem comes from here <a href="{{ url_for('post')}}">.
What this tells Flask is to make a url for post, which is something you have defined in views as def post(argument) but you are not providing an argument. So if for example you are making you are taking your posts based on id, your view would would ask for /<int:post_id>/ in url and post_id would be passed as an argument based on which you would find the specific post and pass that to the template.
Your url_for should reflect this, you should have {{ url_for('post', post_id=title[1]) }} or wherever you are storing your equivalent of post_id (maybe that's title for you).
Edit:
Baed on your edit, your problem is that you are not telling Flask which post to fetch. You need either ID, or slug, or something that will go in the url and will tell you which post you are looking for. Your function right now is static and is always fetching the first entry in your database. The changes required are:
#app.route('/')
def index():
db = connect_db()
titles = db.execute('select title, id from entries')
titles = titles.fetchall()
author = db.execute('select author from entries order by id desc')
author = author.fetchone()
return render_template('index.html', titles=titles, author=author[0])
#app.route('/post/<int:post_id>/')
def post(post_id):
db = connect_db()
post_text = db.execute('select post_text from entries where id = ?', post_id)
post_text = post_text1.fetchone()
author = db.execute('select author from entries where id=2')
author = author.fetchone()
return render_template('post.html', post_text1=post_text, author=author)
<a href="{{ url_for('post', post_id=title[1])}}">
Also your author fetching is weird, you should have them stored (at least their ids) next to entries. Then I'd recomend some naming changes etc. It's hard to just answer the question and not write the code for you, as this is a site for answering specific questions, not writing code on demand :) Try to understand what I wrote here, play around with it a bit more etc. to fully undnerstand.
tl;dr: Posts have to get an argument and then fetch a post identified by that argument, the program can't magically tell which post you clicked on.
I am trying to make a web app like a mini-tweets. The posts are pulled out from a database and I want to have an 'up vote' button for each post, like the following picture.
Each post has an id, author, body, and likes property. When an up vote is clicked, the likes property needs to be updated.
My question is how to determine which button is clicked. What would be a good strategy in this case for the route() function and the html template?
I was thinking of adding a name to each button and put post.id in the name, then check if request has it. But the number of posts are not known before hand, how should I write the request check in route() function?
My current template is as follows
<table class="table table-striped">
{% for post in posts %}
<tr>
<td> {{ post.id }} </td>
<td> <img src="{{ post.author.avatar(50) }}"> </td>
<td> <b>{{ post.body }}</b> </td>
<td> <button type="button" name='{{'up.'+ post.id|string}}' class="btn btn-default">
<span class="glyphicon glyphicon-thumbs-up" aria-hidden="true"></span>
</button>
{{ post.likes}} </td>
</tr>
{% endfor %}
</table>
and the current route() is like this
#bbs.route('/', methods=['GET', 'POST'])
def index():
posts = Post.query.all()
return render_template('bbs/index.html', posts=posts)
A clean way to do that would be to add a data attribute, in your button tag and do one ajax request per upvote / downvote.
https://developer.mozilla.org/en/docs/Web/Guide/HTML/Using_data_attributes
In your case, it would be called data-id.
Then in your javascript, when the button is clicked, get this data attribute value, and craft your url as such :
/upvote/<data-id>
And call it using an ajax GET request (so the page doesn't refresh).
Now on flask side get the id as such :
#app.route('/upvote/<post_id>')
def upvote(post_id):
print('%s upvoted' % post_id)
# do your db update here and return a json encoded object
And on javascript side again, when you get your answer from flask, update your button accordingly.
Assuming you put another class in your upvote button for instance : upvote_button and you use jQuery, your javascript could look like that :
<script type='text/javascript'>
$('.upvote_button').click(function(ev){
var id = $(ev.currentTarget).attr('data-id');
$.get( "/upvote/" + id, function( data ) {
// change your button here, and remove its upvote_button class
alert(data);
});
});
</script>