Flask can a route inherit code from another route? - python

Is it possible for a flask app route to inherit code from another flask app route?
Example
#app.route('/')
def home():
# some code
#app.route('/something')
def something():
# inherit code from home function

You could probably write a handler that is called by both functions like this:
#app.route('/')
def home():
shared_code()
#app.route('something')
def something():
shared_code()
# other specific code
def shared_code():
print("this is called by both routes")

Related

Using Flask whit class - Python [duplicate]

I'm learning Flask and am a bit confused about how to structure my code. So I tried to extend Flask main class as follows:
from flask import Flask, ...
class App(Flask):
def __init__(self, import_name, *args, **kwargs):
super(App, self).__init__(import_name, *args, **kwargs)
Note that I am aware of that this may be a completely wrong approach.
So that when I want to start the app I do:
app = App(__name__)
if __name__ == '__main__':
app.run()
This way I can order my methods and routes in the class, but the problem is when using self-decorators:
#route('/')
def home(self, context=None):
context = context or dict()
return render_template('home.html', **context)
Which raises an error as unresolved reference 'route'. I guess this is not the way I should be structuring the app. How should I do it instead or how do I get the error fixed?
Doing this doesn't make sense. You would subclass Flask to change its internal behavior, not to define your routes as class methods.
Instead, you're looking for blueprints and the app factory pattern. Blueprints divide your views into groups without requiring an app, and the factory creates and sets up the app only when called.
my_app/users/__init__.py
from flask import Blueprint
bp = Blueprint('users', __name__, url_prefix='/users')
my_app/users/views.py
from flask import render_template
from my_app.users import bp
#bp.route('/')
def index():
return render_template('users/index.html')
my_app/__init__.py
def create_app():
app = Flask(__name__)
# set up the app here
# for example, register a blueprint
from my_app.users import bp
app.register_blueprint(bp)
return app
run.py
from my_app import create_app
app = create_app()
Run the dev server with:
FLASK_APP=run.py
FLASK_DEBUG=True
flask run
If you need access to the app in a view, use current_app, just like request gives access to the request in the view.
from flask import current_app
from itsdangerous import URLSafeSerializer
#bp.route('/token')
def token():
s = URLSafeSerializer(current_app.secret_key)
return s.dumps('secret')
If you really want to define routes as methods of a Flask subclass, you'll need to use self.add_url_rule in __init__ rather than decorating each route locally.
class MyFlask(Flask):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.add_url_rule('/', view_func=self.index)
def index(self):
return render_template('index.html')
The reason route (and self) won't work is because it's an instance method, but you don't have an instance when you're defining the class.

Is it possible to dynamically set the name of a decorator in python?

So, I was studying the FLASK framework in python and made my very first simple program and by default I've seen people using app = Flask(__name__) and just below that line they use the decorator #app.route("/"),So I thought that what would happen if I change the name of the variable to something else? Like in the code below I've changed it to something = Flask(__name__) so now I'm confused that how does it still work when I decorate the function index() with #something.route("/") ,is the name of the decorator function defined in FLASK changing dynamically? and if so how can I make my own decorators like this so that they too change their names dynamically?
from flask import Flask
something = Flask(__name__)
#something.route("/")
def index():
return "Hello, World!"
Decorator is just a syntactic sugar:
def decorator(func):
pass
#decorator
def decorated():
pass
is the same as:
def decorator(func):
pass
def decorated():
pass
decorated = decorator(decorated)
The decorator name is nothing more than a function that accepts one argument. You could even use print function as a decorator. Any valid callable will do:
#print
def index():
pass
Obviously that makes little sense, because:
def index():
pass
index = print(index)
Anyway that's how this could be implemented in flask
class Flask:
def route(self, url):
def wrapper(func):
# register route for url
return func
return wrapper
something = Flask()
#something.route("/")
def index():
pass
something.route("/") is a function call that returns the real decorator which is actually the inner function named wrapper.
So you can even do something like this:
something_route_index = something.route("/")
#something_route_index
def index():
pass

Flask - avoiding having code in controller

I'm learning Flask and all the router examples I see look like this:
#app.route('/')
def hello():
name = request.args.get("name", "World")
return f'Hello, {escape(name)}!'
I don't want any code in my controller except:
#app.route('/')
def hello():
mycode.doHelloWorld()
return mycode.sayHelloWorld()
I like my code to be reusable and testable and if it's in the Flask controller it's neither.
Can someone point me to examples of using Flask with the business logic/code separate from the controller?
You can try defining a function which returns a similar output given a request parameter like so:
def sayHelloWorld(request):
name = request.args.get("name", "World")
return f"Hello, {name}!"
#app.route("/")
def hello():
return sayHelloWorld(request)
or based on the code you provided, you can create a class which contains reusable code snippets as static functions
class ReusableCode:
#staticmethod
def sayHelloWorld(request):
name = request.args.get("name", "World")
return f"Hello, {name}!"
#app.route("/"):
def hello():
return ReusableCode.sayHelloWorld(request)

Using routes in classes

I am trying to rewrite some working code as a class.
A minimal working code:
from flask import Flask
app = Flask(__name__)
#app.route("/1")
def func_1():
return "view 1"
#app.route("/2")
def func_2():
return "view 2"
app.run()
How to write it as a class with the route defined during the object instantiation?
I only want it clean: after instantiating an object I want the respective route already working with no extra lines of code.
This is the closest I get to:
from flask import Flask
class NewView:
def __init__(self, url, string):
self.string = string
self.server = Flask(__name__)
self.server.add_url_rule(url, 'index', self.index)
def index(self):
return self.string
v1 = NewView("/1", "view 1")
v2 = NewView("/2", "view 2")
v1.server.run()
This, of course, recognizes /1 as route for v1.index(), but /2 doesn't work.
The ideal would be something like the following but I cannot make it work:
from flask import Flask
app = Flask(__name__)
class NewView:
def __init__(self, url, string):
....
app.add_url_rule(url, ...?..., self.index)
def index(self):
return self.string
v1 = NewView("/1", "view 1")
v2 = NewView("/2", "view 2")
app.run()
First, your mistake:
def __init__(self, url, string):
self.string = string
self.server = Flask(__name__)
self.server.add_url_rule(url, 'index', self.index)
Because you have two instances of this class, there are two Flask objects. You only run the second one.
What you're immediately trying to do can be done like this:
import flask
# There can be only one!
app = flask.Flask(__name__)
class MyView:
def __init__(self, url, name, string):
self.url = url
self.string = string
app.add_url_rule(url, name, self.serve)
def serve(self):
return self.string
view1 = MyView('/1', name='view1', string='This is View 1.')
view2 = MyView('/2', name='view2', string='This is View 2, not view 1.')
app.run()
The above code will work and do what you expect. Something to note is that, since Flask likes names for unique routes, I have you passing in a name for each route. That way, url_for('view1') and url_for('view2') work.
Having said all that, the community has largely already accomplished much of this Pluggable Views. Check it out.
I think that if your goal is to keep code clean, you should avoid creating objects that are never used. The class based views in flask. The as_view() method that is being passes is class method, so also here there is no need to create a never used object. The process of registring urls belongs to creation of an app, not separate objects (that's how it works in Django for instance). If I were you I would go with something similar to this:
from flask import Flask
from flask.views import View
def init_app():
app = Flask(__name__)
app.add_url_rule('/', view_func=NewView.as_view('index'))
return app
class NewView(View):
def dispatch_request(self):
return 'Test'
app = init_app()
app.run()

flask sub function not yielding results

I have a bunch of code (1300 lines) that is working correctly and I am trying to incorporate flask into the picture. In order to do this, I an trying to use flask.Response to call a function within my method, that calls another method in my class.
Here is test code that re-creates my problem.
#!/usr/bin/env python
import flask
class TestClass(object):
app = flask.Flask(__name__)
def __init__(self):
pass
def worker(self):
yield 'print test\n'
#app.route('/')
def test_method_get_stuff():
return flask.render_template('index.html')
#app.route('/', methods=['POST'])
def test_method_post_stuff():
def test_method_sub_function():
tc.worker()
return flask.Response(test_method_sub_function(),mimetype= 'text/plain')
tc = TestClass()
tc.app.run(debug=True)
index.html just has a text box with a submit button.
The issue I have is once you click the submit button, the request goes through sucessfully but the page is blank with no errors in the python command line or in the browser, and what I expect to happen is to show in plain text "print test" with a newline.'
Any assistance would be appreciated. I am trying to avoid completely re-writing all my code. With the understanding that i will have to replace 'print' with 'yield' commands in my code.
Your nested test_method_sub_function() function doesn't return anything; it simply creates the generator (by calling a generator function), then exits.
It should at the very least return the tc.worker() call:
def test_method_sub_function():
return tc.worker()
at which point the route works. You may as well skip this nested function however and use tc.worker() directly:
#app.route('/', methods=['POST'])
def test_method_post_stuff():
return flask.Response(tc.worker(), mimetype='text/plain')
One note: although your use of the Flask object as a class attribute happens to work, you should to put it in a class. Leave the app object and routes outside of the class:
import flask
class TestClass(object):
def worker(self):
yield 'print test\n'
tc = TestClass()
app = flask.Flask(__name__)
#app.route('/')
def test_method_get_stuff():
return flask.render_template('index.html')
#app.route('/', methods=['POST'])
def test_method_post_stuff():
return flask.Response(tc.worker(), mimetype='text/plain')
app.run(debug=True)

Categories

Resources