Say I have an app created like this:
class Parent:
def __init__(self):
self.value = 4
self.app = create_app()
if __name__ == '__main__':
parent = Parent()
parent.app.run(debug=True)
With registered blueprints in some __init __.py file from a module containing the static, templates folders etc:
def create_app():
app = Flask(__name__)
app.config['SECRET_KEY'] = 'Heya!'
from .views import views
app.register_blueprint(views, url_prefix='/')
return app
And with a views.py file containing this:
views = Blueprint('views', __name__)
#views.route('/')
def index():
return render_template("index.html")
Is there a nice way to to access methods or properties from the parent class inside the route?
Of course this doesn't work but for explanation:
#views.route('/')
def index():
value = parent.value
return render_template("index.html")
Or more generally, how can I reach objects outside the app that maybe run in different threads for example? Normally I would pass the parent, but I have no idea how to achieve this here.
Related
i am trying to generate Flask route using a basic DI i.e mapping methods as route handlers, i am a total beginner at Flask so mind my basic skills
class myClass():
def __init__(self):
self.dbConnObj = DbToolsMySql('someconnection', 'slave')
self.dbConnObj.connect()
self.blueprint = Blueprint('myClass', __name__)
self.blueprint.add_url_rule('/my_method', view_func=self.my_method)
def my_method(self, event):
retun "hello"
and then in my handler file
from flask import Flask
from flask_restful import Api, Resource
from src.app.services.myClassimport myClass
app = Flask(__name__)
app.register_blueprint(myClass.blueprint)
if __name__ == "main":
app.run()
Quite simple ehh???? but not working... i am getting following message
Not Found The requested URL was not found on the server. If you
entered the URL manually please check your spelling and try again.
typically you add routes to the Flask app with decorators like so:
app = Flask(__name__)
#app.route('/some-endpoint')
def some_endpoint_handler():
# do something
pass
Or you can add without a decorator like so:
def some_endpoint_handler():
# do something
pass
app = Flask(__name__)
app.route('/some-endpoint', methods=['GET'])(some_endpoint_handler)
So in your scenario, you can pass the app.route call to your myClass object and set the route like this:
class myClass():
def __init__(self, router):
self.dbConnObj = DbToolsMySql('someconnection', 'slave')
self.dbConnObj.connect()
self.blueprint = Blueprint('myClass', __name__)
#self.blueprint.add_url_rule('/my_method', view_func=self.my_method)
router('/my_method', ['GET'])(self.my_method)
def my_method(self, event):
retun "hello"
myObj = myClass( app.route )
or, invert the dependency:
app = Flask(__name__)
#app.route(myClass.blueprint.some_endpoint_string)
def some_endpoint_handler():
myClass.blueprint.call_some_endpoint_handler()
pass
if __name__ == "main":
app.run()
the docs suggest using factory function.
def create_app():
app = Flask(__name__)
return app()
so I don't have access to my app when I'm writing my code,
for this porpuse there is an object called " current_app " in flask module,
so I did this and I got " out of application context error "
#current_app.before_request
def before_req():
whatever...
how can I define before request functions when I'm using a factory function?!
You can define your before_request function inside create_app function:
def create_app():
app = Flask(__name__)
#app.before_request
def before_request(response):
response.headers['Access-Control-Allow-Origin'] = '*'
return response
return app
If you use Flask Blueprints, you define before_request function for your blueprint like this:
from Flask import Blueprint
my_blueprint = Blueprint('my_blueprint', __name__)
#my_blueprint.before_request
def before_request(response):
response.headers['Access-Control-Allow-Origin'] = '*'
return response
I have base_blueprint like that:
from flask import (
jsonify,
Blueprint,
)
class RestBlueprint(object):
def __init__(self, db_model):
self.blueprint = Blueprint(db_model.__tablename__, db_model.__tablename__, url_prefix='/' + db_model.__tablename__ + '/')
self.db_model = db_model
#self.blueprint.route("/<entity_id>", methods=["GET"])
def get_by_id(entity_id):
response = get_item()
return jsonify(response)
I want to inherit this blueprint by other blueprints like that:
from rest_blueprint import RestBlueprint
class UserRestBlueprint(RestBlueprint):
def __init__(self, db_model):
super(UserRestBlueprint, self).__init__(db_model)
#self.blueprint.route("/<user_id>", methods=["GET"])
def get_by_id(user_id):
response = get_item()
del response["password"]
return jsonify(response)
This is a basic example and the reason I want to do it that way is to have base blueprint used for most of my models for CRUD and have custom blueprints for 4-5 models. The problem that I have is that I can't override base blueprint crud methods and I was curious if there is any way to do that in order to have custom CRUD methods for custom blueprints.
Any help is appreciated!
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.
I'm trying to setup a json service with a dynamic route: /action/{id}
I get a 404 when I navigate to: http://example.com:8080/action/test
Based on this documentation, it seems like my routing is configured correctly, but it is not.
Any idea on what I'm doing wrong here?
from wsgiref.simple_server import make_server
from pyramid.config import Configurator
from pyramid.view import view_config
#view_config(route_name="action", renderer="json")
def run_action(self):
id = self.request.matchdict['id']
return {'id': id}
def main():
config = Configurator()
config.add_route('action', '/action/{id}')
app = config.make_wsgi_app()
return app
if __name__ == '__main__':
app = main()
server = make_server('0.0.0.0', 8080, app)
server.serve_forever()
Put a call to config.scan() in your main() function:
def main():
config = Configurator()
config.add_route('action', '/action/{id}')
config.scan()
app = config.make_wsgi_app()
return app
The #view_config decorator doesn't do anything on its own. You must call config.scan(), which will then go and look for all #view_config declarations that have a route_name matching one of config's routes:
config.add_route('foo')
config.scan()
will detect:
#view_config(route_name="foo")
Also, if you're going to have run_action as a standalone function (and not a class method), it should accept a single argument, 'request' (not 'self' as in your excerpt):
#view_config(route_name="action", renderer="json")
def run_action(request):
id = request.matchdict['id']
return {'id': id}
If you do plan on having run_action as a class method, you need to initialize that class correctly, and decorate just the class method:
class MyArbitraryClass():
def __init__(self, request):
self.request = request
#view_config(route_name="action", renderer="json")
def run_action(self):
id = request.matchdict['id']
return {'id': id}
Pyramid Documentation:
http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/project.html
views.py
from pyramid.view import view_config
#view_config(route_name="action", renderer="json")
def run_action(request):
id = request.matchdict['id']
return {'id': id}
def main():
config = Configurator()
config.add_route('action', '/action/{id}')
app = config.make_wsgi_app()
return app
_ init_.py
from pyramid.config import Configurator
def main(global_config, **settings):
""" This function returns a Pyramid WSGI application.
"""
config = Configurator(settings=settings)
config.add_route('action', '/action/{id}')
config.scan()
return config.make_wsgi_app()