Create dynamic URLs in Flask with url_for() - python

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')

Related

How to create a global variable for render_template()?

I have a simple task: to pass the same variable for different routes in the render_template() function. This value is in the base template and I need to pass it on every render_template() function. Can I set this value as a global so that I don't have to set it in every function for different routes?
#app.route('/hello')
def hello(name=None):
return render_template('hello.html', value=value)
#app.route('/bye')
def bye(name=None):
return render_template('bye.html', value=value)
To make variables available to templates without having to burden your routes with passing those variables, use Flask context processors. See https://flask.palletsprojects.com/en/2.1.x/templating/#context-processors for details an an example.
Here's one that I use to 'cache bust' CSS so that browsers won't accidentally use stale versions.
style_css_path = os.path.join(os.path.dirname(__file__), 'static', 'style.css')
style_css_mtime = int(os.stat(style_css_path).st_mtime)
#app.context_processor
def cache_busters():
return {
'style_css_mtime': style_css_mtime,
}
The base template can then do
<link rel="stylesheet"
href="{{ url_for('static', filename='style.css') }}?v={{ style_css_mtime }}" />
Any template that uses base.html inherits this behavior without routes that use that template having to pass style_css_time.
You could use a partial from functools like this:
from functools import partial
# Define a function that takes 2 parameters
def someFunc(a,b):
print(f'Called with a:{a} and b:{b}')
# Define a "partial" where the parameters are partially pre-filled in
p1 = partial(someFunc, b="I was added for free")
# Now call the already partially defined function "p1"
p1("Hello")
Result
Called with a:Hello and b:I was added for free
I found the correct solution to my question in the Flask documentation:
Context Processors
To inject new variables automatically into the context of a template, context processors exist in Flask. Context processors run before the template is rendered and have the ability to inject new values into the template context. A context processor is a function that returns a dictionary. The keys and values of this dictionary are then merged with the template context, for all templates in the app:
#app.context_processor
def inject_user():
return dict(user=g.user)
The context processor above makes a variable called user available in the template with the value of g.user. This example is not very interesting because g is available in templates anyways, but it gives an idea how this works.

Python Flask Jinja Dynamic routing

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.

Python: Sending to a certain URL based on form submission

I'm trying to create a search bar where it will send users to certain URLs based on the query they typed on the "result" page, e.g. "/results?<form_search>". I've successfully made the version where the result page URL is /results but this isn't really what I want.
Here's the HTML script:
<!--index.html-->
<form action="{{ url_for('search') }}" method="post">
<input type="text" id="search" name="form_search" placeholder="Type here">
</form>
Here's the Python script where I direct the result to /results URL:
#app.py
#app.route("/")
def index():
return render_template("index.html")
...
# I want to direct this to "/results?<form_search>"
# I think I need to put the line below somewhere but I'm not sure where
# form_search = request.form.get("form_search")
#app.route("/results", methods=["POST"]) # Want to change it to "/results?<form_search>"
def search(form_search):
...
return render_template("results.html", form_search=form_search, results=results)
Anyone can help?
I barely worked with flask but if you want to have the dynamic URL you need to add it in your #app.route decorator, e.g.: If I want a username to be posted in the URL this is what it would look like:
#app.route("/<username>") # str,int,uuid,float,path also works
def user_name(username=None, post_id=None):
return render_template("index.html", name=username)
When it comes to getting the data from the form I can show you a similar example as I did in django (I didnt work with flask a while so you might need to experiment a bit yourself) - This is a method as it is created in a class:
def get_queryset(self):
query = self.request.GET.get(
"searchrecipe") # searchrecipe is the name of our input form, means: the value we enter in the form -> This might also work for FLASK, get the data with request.get and FORM NAME
object_list = Recipe.objects.filter(name__icontains=query) #This filters the data in my database (aftger name) so not relevant for you
return object_list

python flask url_for is throwing constant werkzeug build errors

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') }}

Flask URL Routing

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.

Categories

Resources