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()
Related
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.
I am trying to create a simple Rest API.
Even if it is simple, I don't want to mix everything in a single file.
Therefore I have defined separate classes
Here is some of my files
app = Flask(__name__)
if __name__ == '__main__':
api = PostApi(app)
api.setup()
api.set_routes()
app.run(debug=True)
Post API class
class PostApi(object):
BASE_API_ROUTE = '/post'
def __init__(self, app):
super(PostApi, self).__init__()
self.app = app
def setup(self):
self.api = Api(self.app)
self.app.config['SECRET_KEY'] = SECRET['digest_key']
def set_routes(self):
self.api.add_resource(PostCategories, self.BASE_API_ROUTE + "/categories")
self.api.add_resource(PostCatalog, self.BASE_API_ROUTE + "/catalog")
self.api.add_resource(PostTags, self.BASE_API_ROUTE + "/tags")
And for example one of my endpoint classes
class PostTags(Resource):
def __init__(self):
super(PostTags, self).__init__()
def get(self):
return {'hello': 'world'}
It works, but I need to add authentication for my routes.
As you can see I am not using route decorators like app.route instead I am using the library flask_restful.
I need to protect my routes with the Digest Auth in this case. However, I am not sure how to do this, because I am not using decorators
I am a newbie developer. Could you suggest how to keep my endpoints separated and apply some protection to my routes.
You can use before_request. This will be called before every request on every route.
something like this:
#app.before_request
def before_request():
//add your logic here
there's also before_first_request.
visit Flask Documentation for more info.
I am working on setting up unit tests in my flask project right now. My test file is below:
import flask_testing
import unittest
from flask import Flask
from flask_testing import TestCase
class MyTest(TestCase):
def setUp(self):
pass # Executed before each test
def tearDown(self):
pass # Executed after each test
def create_app(self):
app = Flask(__name__)
# app.config['TESTING'] = True
return app
def test_greeting(self):
response = self.client.get('/')
print("should return 404 on landing page")
self.assertTemplateUsed('index.html')
self.assertEqual(response.status_code, 200)
if __name__ == '__main__':
unittest.main()
When I run these tests the assertTemplateUsed does not return a template and the response.status_code is 404. I imagine this is because self is not actually my application for some reason? When I run the app the root address definitely returns index.html.
Am I setting up create_app wrong? Any help is appreciated.
You need to create your Flask app instance in the setUp() function. At the moment the create_app() function doesn't get called at all.
Change your code like this:
import flask_testing
import unittest
from flask import Flask
from flask_testing import TestCase
class MyTest(TestCase):
def setUp(self):
self.app = Flask(__name__)
self.app_context = self.app.app_context()
self.app_context.push()
self.client = self.app.test_client(use_cookie=True)
def tearDown(self):
self.app_context.pop()
def test_greeting(self):
response = self.client.get('/')
print("should return 404 on landing page")
self.assertTemplateUsed('index.html')
self.assertEqual(response.status_code, 200)
if __name__ == '__main__':
unittest.main()
The setUp() function gets called prior to each test function. At first you will create a new instance of your Flask app. If you want to access items in your application context it is good practice to push it in your setUp() function and pop it in your tearDown() function. You can leave this out if you don' t access app_context items (like Database session objects) from your test function. At last you need to creat the test client in your setUp() function. You missed that part in your post but I guess you did it somewhere else in your code.
In your setUp function, you need to provide a test client to make the requests. Try something like this.
def setUp(self):
# this test client is what flask-testing will use to make your requests
self.app = app.test_client()
Check this out for more information How to Test a Flask Application.
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.
Suppose I need to do before_request for each flask servers
How can I share the following snippet to each servers without COPY-PASTE
#app.before_request
def before_request(*args, **kwargs):
params = get_params()
if params.has_key('start_dt') and params.has_key('end_dt'):
g.mongo_query = Mongo.get_date_range_query(params)
else:
g.mongo_query = {}
You could use application factory for this. If you initialize your flask applications like so:
from flask import Flask
import yourdb
def create_app(config_filename):
app = Flask(__name__)
app.config.from_pyfile(config_filename)
yourdb.init_app(app)
#add_extensions
#add_blueprints/views
# ... some other configuration ...
#app.before_request
def before_request(*args, **kwargs):
#Your code
return app
From manage/run, you would then
from somewhere import create_app
app = create_app(<your_config>)