Access flask app context in worker to access database - python

I am trying to access db.session in a Flask-RQ job to update my database.
The thing is that I am not able to do it as my app context is not known by the worker which is executing jobs.
I am also using Flask Blueprints to structure my application so I am not able to use app context with from app import app.
Below my application structure:
--> app
--> __init__.py
--> jobs.py
--> routes
--> routes.py
config.py
I created a Blueprint for jobs.py but when I trigger my job in routes.py file I have an error when trying to do query with db.session (note that db is imported with from app import db and session with from flask import session).
RuntimeError: No application found. Either work inside a view function or push an application context.
The job is pretty simple:
#rq.job
def try_rq():
print("Starting task")
db.session.query(...)
print("Task completed")
I do not know how to make my worker knowing the application context and so be able to use db.session to update my database.
Note that without database update the job is working fine.

Related

How to add flask-admin to my existing flask

For the past two days I've been trying to intergrate flask-admin to my already existing flask application. But the problem is that I keep getting the same error:
builtins.AssertionError
AssertionError: A name collision occurred between blueprints <flask.blueprints.Blueprint object at 0x000001D8F121B2B0> and <flask.blueprints.Blueprint object at 0x000001D8ECD95A90>. Both share the same name "admin". Blueprints that are created on the fly need unique names.
and that error comes from this block of lines:
Main flask application:
app.route("/admin")
def admin():
if not session.get('logged_in'):
return redirect(url_for('login'))
return adminScreen.adminPage()
admin.py
def adminPage():
admin=Admin(app)
admin.add_view(ModelView(User, db.session))
admin.add_view(ModelView(Role, db.session))
admin.add_view(ModelView(PointOfSale, db.session))
return admin
And what I want to do is to manage the users that I already have in my database by using the functions that flask-admin provide.
So my question is; is there a simple way to route flask-admin to my pre-existing flask application?
P.S I already know that there is this post from May of 2018, but I have no idea how to implement the solution that was provided.
You don't have to create an app.route("/admin") yourself. That is provided by the built-in blueprint from flask-admin.
In order to use blueprints correctly you should update your app to use app factory instead global variable. Otherwise you cannot have multiple instances of the application.
In existing project it may require some work to do but it's worth it.
Example factory may looki like this:
def create_app(config_filename):
app = Flask(__name__)
app.config.from_pyfile(config_filename)
from yourapplication.model import db
db.init_app(app)
from yourapplication.views.admin import admin
from yourapplication.views.frontend import frontend
app.register_blueprint(admin)
app.register_blueprint(frontend)
return app
You can find more information here:
http://flask.pocoo.org/docs/1.0/patterns/appfactories/

Access the 'g' global proxy when creating an app using a factory in Flask

When in debug mode I want to add a handle to a memcached server in g. A nice place to do that is in the factory create method (create_app in the tutorial).
However, access to g results in a RuntimeError: Working outside of application context. I could register a method using Flask.before_request, but I do not want to have a check for DEBUG mode running every time a user connects.
From what I've read, each request seems to get its own context instance, and with it its own g. Is there another way to retain per-app data for use in this way?
from flask import Flask
from flask import current_app
def create_app():
app = Flask(__name__)
# set your function
setattr(app, 'my_func', 'function')
return app
app = create_app()
#app.route('/')
def index():
return getattr(current_app, 'my_func')
if __name__ == '__main__':
app.run()

route endpoint conflicts when generating sphinx doc for flask restful api

I'm trying to build documentation for a Flask webapp that includes a REST-like API built into it. I'm using sphinx, specifically the httpdomain extension from sphinxcontrib, using the autohttp.flask module to auto-generate my Flask docs, and the autohttp.qrefflask module to auto-generate a quick reference table to go along with it. However, when I try to build my sphinx docs (make html), I'm running into the error of conflicting route endpoints
Exception occurred:
File "/Users/../anaconda2/lib/python2.7/site-packages/flask/app.py", line 1051, in add_url_rule
'existing endpoint function: %s' % endpoint)
AssertionError: View function mapping is overwriting an existing endpoint function: api.View1:add_config
I only really care about generating documentation for my API and none of the Flask web routes, so I've restricted my sphinx documentation to only build the api blueprints. Here is my sphinx api.rst
.. qrefflask:: myapp.web:create_app(debug=True)
:undoc-static:
:endpoints:
:blueprints: api
:order: path
.. autoflask:: myapp.web:create_app(debug=True)
:undoc-static:
:endpoints:
:blueprints: api
:order: path
My Flask app and Blueprint layout is as follows:
myapp/
api/
__init__.py (api blueprint defined here)
view1.py
view2.py
view3.py
web/
__init__.py (main Flask app created here via create_app)
I'm wondering if it's a problem with how I'm registering the blueprint, and that sphinx somehow is registering it twice, but I don't understand it.
My api.__init__.py basically has my Blueprint definition and a few custom error handlers:
from flask import Blueprint, jsonify
theapi = Blueprint("api", __name__, url_prefix='/myapp/api')
#theapi.errorhandler(500)
def internal_server_error(err):
messages = {'error': 'internal_server_error',
'message': err.description,
'traceback': get_traceback(asstring=True)}
return jsonify({
'api_error': messages,
}), 500
while my main Flask app creation, web.__init__.py just imports this and registers everything:
def create_app(debug=False, local=False):
from myapp.api import theapi as api
from myapp.api.view1 import View1
...
app = Flask(__name__, static_url_path='/myapp/static')
...
View1.register(api)
app.register_blueprint(api)
return app
If I move the api blueprint definition and error_handlers into the main app creation, everything works fine. But then that breaks the modularity of it. I'd like to keep my api stuff inside the api module. Also, if remove either the main autoflask or qrefflask generation, and only use one, everything works fine. But I'd really like to have the quick reference guide. The code itself runs fine, but the damn documentation is failing to build. Does anyone have any suggestions?

Insert a document with Flask-PyMongo

I have a MongoDB database and I want to use Flask-PyMongo to work with it in my Flask app. How do I add a database and a collection so I can add user documents?
from flask import Flask, render_template, url_for
from flask.ext.pymongo import PyMongo
app = Flask(__name__)
app.config['MONGO_DBNAME'] = 'microblogdb'
app.config['MONGO_URI'] = 'mongodb://briangunsel:password#microblog:27017/microblogdb'
mongo = PyMongo(app, config_prefix='MONGO')
#app.route('/')
def home():
posts = mongo.db.posts.find({})
return render_template('users.html', posts=posts)
app.run(debug=True)
Update:
With only that code above, when I start up the server (python init.py) and I go to load the web page, it loads for about 10 seconds and then gives me this error https://gist.github.com/anonymous/62ca41e98e67b304838d. I am running the database microblogdb in another cmd prompt, and I set the mongo --dbpath to \data\, which is a folder I created in the microblog folder. Through the mongo interpreter, I added a posts collection, it is still giving me the same error.
mongo.db.users returns the users collection on the database you configured. Flask-PyMongo is using the PyMongo driver, which has extensive documentation. PyMongo's tutorial explains how to insert a document. You already have code that fetches the users who have online=True.
app.config['MONGO_URI'] = 'mongodb://username:password#host:port/db_name'
user_id = mongo.db.users.insert_one({'name': 'david'}).inserted_id

Flask per-blueprint error pages

I have a flask application that looks somewhat like this:
app.py
blueprints/
www.py
shop.py
app.py imports blueprint objects from each of the files in the blueprints directory and registers them with the Flask object in app.py with an appropriate subdomain (also imported from the file). Each blueprint registers error handlers, however these are only invoked when a view manually calls abort(), not by general errors (i.e. calling a non existent URL on the subdomain managed by shop.py invokes the error handler on app.py instead.)
Is there any way to force flask to pass errors to the blueprint that is handling the subdomain in which that error is occurring?
Flask's documentation says that this is not possible for 404s and 500s. If you need this functionality you might be able to use a wildcard route in your blueprint to handle 404s:
#a_blueprint.route("<path:invalid_path>")
def missing_resource(invalid_path):
return "There isn't anything at " + invalid_path, 404
You can use current_app and put it in the blueprints. Something like:
shop.py
from flask import current_app
#current_app.errorhandler(404)
def page_not_found(e):
return redirect(url_for('shop.index'))

Categories