I am having a flask url_for('') error in a very simple application.
from flask import Blueprint, render_template, abort
from jinja2 import TemplateNotFound
base = Blueprint('main', __name__)
#base.route('/', defaults={'page':'home'})
#base.route('/<page>')
def show(page):
try:
return render_template('%s.html'%page, name='my name is')
except TemplateNotFound:
abort(404)
the above is my blueprints file, those routes work fine but if I try to do
with flask.test_request_context():
print url_for('home') #home.html or any other forms
I just get this error:
raise BuildError(endpoint, values, method)
werkzeug.routing.BuildError: ('home', {}, None)
can anyone help me figure out what's going on here?
in my html page I can print out the location of static files with:
{{ url_for('static', filename='style.css') }}
but if i try to do:
{{ url_for('home') }}
Again I get the same error. Anyone have some advise as how to proceed?
You're trying to use url_for the wrong way round, I think.
url_for in general maps an endpoint, i.e. a python function/method, to an url. In your case home is the value of a parameter, not an endpoint.
So, instead, use the name of the python function you want the url for:
url_for('show', page='home')
Should be what you're looking for.
When you do {{ url_for('home') }} it doesn't return route of home.html instead it returns the route of a function home, which by the way doesn't exist.
So to fix your problem,
The proper way of using url_for is :
{{ url_for('show') }}
Related
This question already has answers here:
Sending data from HTML form to a Python script in Flask
(2 answers)
Get a variable from the URL in a Flask route
(2 answers)
Closed 1 year ago.
I am trying to make a basic webapp, which takes two basic inputs from the user called "phrase" (The word you want the text to be searched in) and "letters" (The letters you want to look for inside the "phrase" input).
I have used Python (Flask) and a bit of HTML to make it. Everything was fine until I tried to connect the input values from the HTML form to Python using the "request" object of flask. I have attached the Python and HTML code along with the error at the client side and the error at Visual Studio Code, I tried asking my friends for the solution but they were not sure about it either.
Python code-
app = Flask(__name__)
#app.route('/')
def flask_hello():
return 'Please go to: http://127.0.0.1:5000/entry'
#app.route('/search4', methods=['POST'])
def do_search(phrase,letters) -> str:
phrase = request.form['phrase']
letters = request.form['letters']
return str(set(letters)).intersection(str(phrase))
# return(common)
#app.route ('/entry')
def entry_page() -> 'html':
return render_template('entry.html',
the_title='Welcome to search4letters on the web!')
app.run(debug=True)
HTML Code-
{% extends 'base.html' %}
{% block body %}
<h2> {{ the_tile }}</h2>
<form method='POST' action='/search4'>
<table>
<p>Use this form to submit a search request</p>
<tr><td>Phrase:</td><td><input name='phrase' type='TEXT' width='60'></td></tr>
<tr><td>Letters:</td><td><input name='letters' type='TEXT' value='aeiou'></td></tr>
</table>
<p> When you're ready, click this button:</p>
<p><input value='Do it!!' type='submit'></p>
</form>
Error at the client side and VS code is attached too-
I am not sure why this happening, I am not sure if it is a really stupid thing and I am not able to figure it out, I tried looking for a solution but was not able to find any. Hopefully you guys can help me with this, thanks in Advance!
Have a great day ahead.
Idk how it works in Flask, but I think nearly like in Django. It's happening cause your action="url" in form without parameters.
In Django, we can reverse URLs with kwargs in the template for example:
action='{% url "search4" obj.phase obj.letters %}'
also, you have to add parameters in your route view:
#app.route("search/<str:phrase>/<str:letters>/")
On the html page
{{ item.filename }}
On the flask routing code :
#app.route("/<username>/<filename>")
def downloadimage(username, filename):
However, this isn't routing the routing method.
What's the issue here ?
You can use the url_for method here.
Use it like this:
{{ item.filename }}
Here, downloadimage is the name of the function added to the required URL, username and filename are the parameters that should be passed to the function.
I'd like to AJAXify both a login and a signup form on a site. Up to now I've been using WTForms mainly for its built-in CSRF protetion, but for this project I didn't feel like it was worth it -- an extra layer of abstraction, and therefore frustration, for something that should be pretty simple.
So I came across this snippet on Flask's security section:
#app.before_request
def csrf_protect():
if request.method == "POST":
token = session.pop('_csrf_token', None)
if not token or token != request.form.get('_csrf_token'):
abort(403)
def generate_csrf_token():
if '_csrf_token' not in session:
session['_csrf_token'] = some_random_string()
return session['_csrf_token']
app.jinja_env.globals['csrf_token'] = generate_csrf_token
I understand the thought process behind this code. In fact, it all makes perfect sense to me (I think). I can't see anything wrong with it.
But it doesn't work. The only thing I've changed about the code is replacing the pseudofunction some_random_string() with a call to os.urandom(24). Every request has 403'd so far because token and request.form.get('_csrf_token') are never the same. When I print them this becomes obvious -- usually they're different strings, but occasionally, and seemingly with no underlying reason, one or the other will be None or a truncated version of the output of os.urandom(24). Obviously something out of sync, but I'm not understanding what it is.
You can get the convenience of flask-wtf without all the heaviness, and without rolling your own:
from flask_wtf.csrf import CsrfProtect
then on init, either:
CsrfProtect(app)
or:
csrf = CsrfProtect()
def create_app():
app = Flask(__name__)
csrf.init_app(app)
The token will then be available app-wide at any point, including via jinja2:
<form method="post" action="/">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
</form>
(via the docs)
I think your problem is os.urandom function. The result of this function can contains symbols which not will parse properly in html. So when you insert csrf_token in html and don't do any escaping, you have the described problem.
How to fix.
Try to escape csrf_token in html (see docs) or use another approach for generating csrf token. For example using uuid:
import uuid
...
def generate_random_string():
return str(uuid.uuid4())
...
If I'm making a blog site and I want to set up routing such that
#app.route('/<username>/<postname>', methods=['GET'])
routes to the post with name 'postname' of the user with name 'username', how do I get the html to recognize this? I've been trying to do something like
<a href={{ url_for('/', username=user.name, postname=post.name) }}>{{post.name}}</a>
I'm also trying to reconcile this with Flask understanding special keywords /login or /about so that it checks if the user is trying to access those first. How can I implement those checks?
The first argument to url_for in your template should be the name of the view function you decorated:
#app.route('/<username>/<postname>', methods=['GET'])
def view_user_post(username, postname):
^^^^^^^^^^^^^^
Now, you can write this in your template:
{{ url_for('view_user_post', username=user.name, postname=post.name) }}
This lets you change the URL in the route without having to update it elsewhere in your codebase.
Half of my Flask routes requires a variable say, /<variable>/add or /<variable>/remove. How do I create links to those locations?
url_for() takes one argument for the function to route to but I can't add arguments?
It takes keyword arguments for the variables:
url_for('add', variable=foo)
url_for('remove', variable=foo)
The flask-server would have functions:
#app.route('/<variable>/add', methods=['GET', 'POST'])
def add(variable):
#app.route('/<variable>/remove', methods=['GET', 'POST'])
def remove(variable):
url_for in Flask is used for creating a URL to prevent the overhead of having to change URLs throughout an application (including in templates). Without url_for, if there is a change in the root URL of your app then you have to change it in every page where the link is present.
Syntax: url_for('name of the function of the route','parameters (if required)')
It can be used as:
#app.route('/index')
#app.route('/')
def index():
return 'you are in the index page'
Now if you have a link the index page:you can use this:
<a href={{ url_for('index') }}>Index</a>
You can do a lot o stuff with it, for example:
#app.route('/questions/<int:question_id>') #int has been used as a filter that only integer will be passed in the url otherwise it will give a 404 error
def find_question(question_id):
return ('you asked for question{0}'.format(question_id))
For the above we can use:
<a href = {{ url_for('find_question' ,question_id=1) }}>Question 1</a>
Like this you can simply pass the parameters!
Refer to the Flask API document for flask.url_for()
Other sample snippets of usage for linking js or css to your template are below.
<script src="{{ url_for('static', filename='jquery.min.js') }}"></script>
<link rel=stylesheet type=text/css href="{{ url_for('static', filename='style.css') }}">
Templates:
Pass function name and argument.
{{blog.title}}
View,function
#app.route('/blog/post/<string:id>',methods=['GET'])
def get_blog_post(id):
return id
You need to add function means that the page you want to render that function whould be added inside the url_for(function name).
It will redirect to that function and the page will render accordingly.
If this can help, you can override the static folder when declaring your flask app.
app = Flask(__name__,
static_folder='/path/to/static',
template_folder='/path/to/templates')