May I build more than two layers of endpoint in Flask? - python

I know when flask builds large application, it has registered multiple blueprints.
The flask blueprint starts to initial a blueprint object, it has declared name of first layer of endpoint in the same time.
For example:
users_bp = Blueprint('users', __name__)
According to the expression, the name of first layer of endpoint of users_bp is users.
The blueprint object continues to register its view function, it has declared name of second layer of endpoint in the same time.
#users_bp.route('/login')
def login():
# do something
According to the expression, the name of second layer of endpoint of users_bp is login, it's from view name.
If I want to use endpoint to get corresponding url, I should be to do : url_for('users.login').
So it's workflow of building large application from flask tutorial. Is it right?
Let's get back on point. Is it possible to build three layers of endpoint as url_for('api. users.login')?
How do I package the blueprint or flask app to complete my wanted structure? Is it available?

You can set an endpoint within your route decorator, for example:
from flask import Flask, render_template_string
app = Flask(__name__)
#app.route('/', endpoint="this.is.the.home.endpoint")
def index():
_html="<a href='{{url_for('this.is.another.endpoint')}}'>Go to another endpoint</a>"
return render_template_string(_html)
#app.route('/another', endpoint="this.is.another.endpoint")
def another():
_html="<a href='{{url_for('this.is.the.home.endpoint')}}'>Go to the home page</a>"
return render_template_string(_html)
if __name__ == '__main__':
app.run()

Related

Define a common route pass-through or filter for all Python Flask Blueprint Routes

In my Python Flask app I have Blueprint Routes defined that correspond to API endpoints,
# Submit Agreement (Insert or Update)
#bp.route('submitAgreement', methods=['POST'])
#auth.login_required
def submitAgreement():
#...code...
# Get Existing Agreement
#bp.route('fetchAgreement', methods=['POST'])
#auth.login_required
def fetchAgreement():
#...code...
I need to define a common route pass-through or filter that will perform authorization prior to executing the code. The authorization needs to be, if the URL contains the param id=.., check that that ID belongs to the logged-in user.
Is there a way to define a custom "aspect" or filter with this code in Python Flask?
Flask offers an
#app.before_request decorator
You can substitute app for bp to apply the function you define to just the blueprint.

flask Function to create route

i'm building an app similar to myPhpAdmain
i need to allow users in session to create route (aka: #app.route) for the page they require
#app.route('/<x>')
def <x>():
return render_template (<x>+'.html')
where x is a variable that has been given by a user through the front-end
x = request.form.get('x')
how can I allow users to create Pages route like that by a function without allowing them to write it themselves in my flask app ?
Use variable routing:
#app.route('/<x>')
def user_route(x):
return render_template(f"{x}.html")

Getting flask-restful routes from within a blueprint

Is there a way to get the routes defined in a blueprint? I know this (http://flask.pocoo.org/snippets/117/) snippit exists, but requires to have the app initalized to use url_map. Is there a way to view the routes without an application? I'm developing an api with flask-restful and I would like to display the routes from within the blueprint without the app to keep it self contained.
Using the information provided by polyfunc, I was able to come up with this solution:
from flask import Blueprint, current_app, url_for
from flask_restful import Resource, Api
api_blueprint = Blueprint('api', __name__)
api = Api(api_blueprint)
#api.resource('/foo')
class Foo(Resource):
def get(self):
prefix = api_blueprint.name + '.' # registered classes will have this as their prefix
# Get current rules
rules = current_app.url_map.iter_rules()
# Get list from routes registered under the blueprint
routes = [url_for(rule.endpoint) for rule in rules if rule.endpoint.startswith(prefix)]

Flask-Restful ignores blueprint's url_prefix

I want to use Flask blueprints to organize my Flask-Restful resources into separate url prefixes. Regardless of what url prefix I set (during either blueprint creation or registration), everything gets mapped to the raw route paths. How do I correctly use Restful with blueprints?
app = Flask(__name__)
api = Api(app)
api.add_resource(Building, '/<int:id>', endpoint='building')
api.add_resource(Jack, '/<int:id>', endpoint='jack')
building_api = Blueprint('building_api', __name__)
jack_api = Blueprint('jack_api', __name__)
app.register_blueprint(building_api, url_prefix='/buildings')
app.register_blueprint(jack_api, url_prefix='/jacks')
All documentation I can find says that these should now be available at /buildings/<int:id> and /jacks/<int:id>, but both of those urls 404 and instead I can access the building one at /<int:id>. Hard coding the path in add_resource fixes it, but defeats the point of url_prefix.
You need to pass the blueprint to the Api instance, not the app.
building_bp = Blueprint('buildings', __name__)
building_api = Api(building_bp)
building_api.add_resource(Building, '/<int:id>')
app.register_blueprint(building_bp, url_prefix='/buildings')
This is zhe best way to do with blueprint:
from flask import Flask, Blueprint
from flask_restful import Api, Resource, url_for
app = Flask(__name__)
api_bp = Blueprint('api', __name__)
api = Api(api_bp)
class TodoItem(Resource):
def get(self, id):
return {'task': 'Say "Hello, World!"'}
api.add_resource(TodoItem, '/todos/<int:id>')
app.register_blueprint(api_bp)
you should send Blueprint'instance to Api
I do not know why but I struggled using the Blueprint as mentioned in the answers.
But here's a quick solution I found while going through the doc link. Making use of the prefix parameter in Api() does the job.
app = Flask(__name__)
api = Api(app, prefix='/buildings')
Now, all your routes will be prefixed with /buildings. Just make sure you use url_for('link') in places where you might have simply used a /link.
One more strange thing I noticed is that atleast for me, it did not work until I renamed my routes to the same name as their class names. For example, Class Home(Resource) should have a route to /home. Using /homeepage or any other route for Home Class causes an error. Not sure if it is only me.

What is an 'endpoint' in Flask?

The Flask documentation shows:
add_url_rule(*args, **kwargs)
Connects a URL rule. Works exactly like the route() decorator.
If a view_func is provided it will be registered with the endpoint.
endpoint – the endpoint for the registered URL rule. Flask itself assumes the name of the view function as endpoint
What exactly is meant by an "endpoint"?
How Flask Routing Works
The entire idea of Flask (and the underlying Werkzeug library) is to map URL paths to some logic that you will run (typically, the "view function"). Your basic view is defined like this:
#app.route('/greeting/<name>')
def give_greeting(name):
return 'Hello, {0}!'.format(name)
Note that the function you referred to (add_url_rule) achieves the same goal, just without using the decorator notation. Therefore, the following is the same:
# No "route" decorator here. We will add routing using a different method below.
def give_greeting(name):
return 'Hello, {0}!'.format(name)
app.add_url_rule('/greeting/<name>', 'give_greeting', give_greeting)
Let's say your website is located at 'www.example.org' and uses the above view. The user enters the following URL into their browser:
http://www.example.org/greeting/Mark
The job of Flask is to take this URL, figure out what the user wants to do, and pass it on to one of your many python functions for handling. It takes the path:
/greeting/Mark
...and matches it to the list of routes. In our case, we defined this path to go to the give_greeting function.
However, while this is the typical way that you might go about creating a view, it actually abstracts some extra info from you. Behind the scenes, Flask did not make the leap directly from URL to the view function that should handle this request. It does not simply say...
URL (http://www.example.org/greeting/Mark) should be handled by View Function (the function "give_greeting")
Actually, it there is another step, where it maps the URL to an endpoint:
URL (http://www.example.org/greeting/Mark) should be handled by Endpoint "give_greeting".
Requests to Endpoint "give_greeting" should be handled by View Function "give_greeting"
Basically, the "endpoint" is an identifier that is used in determining what logical unit of your code should handle the request. Normally, an endpoint is just the name of a view function. However, you can actually change the endpoint, as is done in the following example.
#app.route('/greeting/<name>', endpoint='say_hello')
def give_greeting(name):
return 'Hello, {0}!'.format(name)
Now, when Flask routes the request, the logic looks like this:
URL (http://www.example.org/greeting/Mark) should be handled by Endpoint "say_hello".
Endpoint "say_hello" should be handled by View Function "give_greeting"
How You Use the Endpoint
The endpoint is commonly used for the "reverse lookup". For example, in one view of your Flask application, you want to reference another view (perhaps when you are linking from one area of the site to another). Rather than hard-code the URL, you can use url_for(). Assume the following
#app.route('/')
def index():
print url_for('give_greeting', name='Mark') # This will print '/greeting/Mark'
#app.route('/greeting/<name>')
def give_greeting(name):
return 'Hello, {0}!'.format(name)
This is advantageous, as now we can change the URLs of our application without needing to change the line where we reference that resource.
Why not just always use the name of the view function?
One question that might come up is the following: "Why do we need this extra layer?" Why map a path to an endpoint, then an endpoint to a view function? Why not just skip that middle step?
The reason is because it is more powerful this way. For example, Flask Blueprints allow you to split your application into various parts. I might have all of my admin-side resources in a blueprint called "admin", and all of my user-level resources in an endpoint called "user".
Blueprints allow you to separate these into namespaces. For example...
main.py:
from flask import Flask, Blueprint
from admin import admin
from user import user
app = Flask(__name__)
app.register_blueprint(admin, url_prefix='admin')
app.register_blueprint(user, url_prefix='user')
admin.py:
admin = Blueprint('admin', __name__)
#admin.route('/greeting')
def greeting():
return 'Hello, administrative user!'
user.py:
user = Blueprint('user', __name__)
#user.route('/greeting')
def greeting():
return 'Hello, lowly normal user!'
Note that in both blueprints, the '/greeting' route is a function called "greeting". If I wanted to refer to the admin "greeting" function, I couldn't just say "greeting" because there is also a user "greeting" function. Endpoints allow for a sort of namespacing by having you specify the name of the blueprint as part of the endpoint. So, I could do the following...
print url_for('admin.greeting') # Prints '/admin/greeting'
print url_for('user.greeting') # Prints '/user/greeting'
Endpoint is the name used to reverse-lookup the url rules with url_for and it defaults to the name of the view function.
Small example:
from flask import Flask, url_for
app = Flask(__name__)
# We can use url_for('foo_view') for reverse-lookups in templates or view functions
#app.route('/foo')
def foo_view():
pass
# We now specify the custom endpoint named 'bufar'. url_for('bar_view') will fail!
#app.route('/bar', endpoint='bufar')
def bar_view():
pass
with app.test_request_context('/'):
print url_for('foo_view')
print url_for('bufar')
# url_for('bar_view') will raise werkzeug.routing.BuildError
print url_for('bar_view')
If you have same class name and want to map with multiple routes, then specify the endpoint, so that framework will differentiate between two:
class ClassName(Resource):
def get(self):
if request.endpoint!='hello':
return {"data": "Hello"}
elif:
return {"data" : "World"}
api.add_resource(ClassName, '/rout1', endpoint = "world")
api.add_resource(ClassName, '/rout2', endpoint="hello")
#app.route('/') #Endpoint
def a_function(): #View function
return 'view'
Inside Flask, every endpoint with its request methods mapped to a view function. When you use app.route decorator you are actually adding a URL rule.

Categories