How should I create a Flask extension which depends on another extension? - python

I want to create a Flask extension which depends on another Flask extension. For the sake of argument, say that it's Flask-Foo, and that it needs Flask-Redis to store some specific data in a Redis database.
I know that I can add an install dependency to Flask-Redis. However I don't understand how I should instantiate and initialize Flask-Redis.
The setup for Flask-Foo sets up the Flask-Redis object. The drawback of this is that it assumes that the app isn't also using Flask-Redis for some other reason, configured explicitly outside of Flask-Foo. If it is, we get two objects which exist side-by-side, which seems wrong.
The user has to themselves instantiate and configure Flask-Redis. Flask-Foo checks that it has been initialized for that app, and complains otherwise. The problem with this is that it seems to impose boilerplate on the user - why should they have to set up Flask-Redis to use Flask-Foo, when they have no other knowledge or interest in the configuration of Flask-Redis? Furthermore, aren't we asking for trouble if this means that Flask-Foo.init_app() always has to be called after Flask-Redis.init_app()?
Don't use Flask-Redis. Use the Redis package directly, and manage the connection in Flask-Foo code. This would probably avoid the above problems. But it seems unelegant - we will basically have to resolve problems solved by Flask-Redis. If Flask-Foo goes on to support an alternative database, it will become complicated as we have to maintain code to manage the different types of connection.
Just to be clear, this is not a question specifically about Flask-Redis or how it works! I just want to understand what is generally the right way to build an extension on top of an extension.

You can pass depend extension to init_app. http://flask.pocoo.org/docs/1.0/extensiondev/
flask_foo/init.py
class FooManager:
def __init__(self, app=None, db=None, **kwargs):
self.app = app
if app is not None:
self.init_app(app, db, **kwargs)
def init_app(self, app, db, **kwargs):
self.db = db
app.config.setdefault('xxx', xxx)
# Bind Flask-Foo to app
app.foo_manager = self
Now, you can get foo_manager object from current_app like this:
models.py
from flask import current_app
db = current_app.foo_manager.db
class XXX(db.Model):
pass
Last, maybe you must register foo by app_context():
run.py
with app.app_context():
FooManager(app, db) # or xx = FooManager(); xx.init_app(app, db)
wonderful, depend extension works good for us.
Other tip: https://stackoverflow.com/a/51739367/5204664

Flask extension has the same structure as a python module. You should specify all requirements in setup.py file.
For example flask-babel
install_requires=[
'Flask',
'Babel>=2.3',
'Jinja2>=2.5'
],

Related

are global variables a good idea for a flask website application?

There is a flask website which accesses some data stored in a database. The data is related to more than one templates of the website, and I would prefer the database not to be accessed again and again for the same info as the user is visiting the website templates, but rather to be stored in variables. Session is not a good idea because of the size of the data. I'm wondering if using global variables for that purpose would be a good idea. Accessing once the database and assigning the data to the global variables, from where it will be available through the templates of the website for as long as the session will last. I would be grateful to know if this is the proper way to achieve it, or there are drawbacks in a way that accessing the database several times if needed, would be a better option. Thank you in advance.
Try with ORM tools like sQLAlchemy, it does most of the heavy weight lifting for you.
https://www.sqlalchemy.org/
Examples available here
https://realpython.com/flask-by-example-part-2-postgres-sqlalchemy-and-alembic/
If your code is not using sqlalchemy and you do not want to do the heavy lifting of refatoring the code for various reasons then you could wrap you database access code in to a class and attach it to the flask app instance.
app.db = DBAccessClass()
In then through the code you's call on the instance attached to the flask app.
This wont solve your issue with making multiple calls to DB for the same data that can be cached.
Then you can use an annotation class that would implement a caching strategy for your DBAccessClass, here is a very simple example:
from functools import wraps, update_wrapper
class cache(object):
def __init__(self):
self.named_caches = {}
def __call__(self, f):
#wraps(f)
def decorated(*args, **kwargs):
key = f.__name__
if key not in self.named_caches:
self.named_caches[key] = f(*args, **kwargs)
return self.named_caches[key]
return update_wrapper(decorated, f)
cached = cache()
class MyDBAccessClass(object):
#cached
def get_some_data(self):
data = query_db()
return data
This might be a short term solution, would strongly encourage to consider sQLAlchemy.

Proper code style in python Flask application

I have a flask app with a single file (app.py) a large code base size of 6K lines which i want to modularize by making Separate files for each group of route handlers.
Which one is the proper approach
creating Class for similar routes like user and giving member functions like login, register
user.py
class User:
def login():
pass
def register():
pass
use it like
user = User()
user.login()
or create a python file user.py and just droping all the functions inside that
user.py
def login():
pass
def register():
pass
and use it like
import user
user.login()
from above mentioned approaches which one will use proper memory and more efficient
You should almost never use classes for flask routes as they are inherantly static, and so are not really suited for having instances made of them
The easiest solution is just to separate related routes into modules, as shown in the second part of your question.
If I were you I would also look into Flask's blueprints, which are specifically designed to group routes together:
http://flask.pocoo.org/docs/1.0/blueprints/
(I would also recommend doing the tutorial for Flask that is available on the Flask website, where you make a small blogging application and blueprints and modularisation are explained http://flask.pocoo.org/docs/1.0/tutorial/)
The latter is Pythonic.
Don't use classes when you don't need instance data; use modules.

Use Flask-SQLAlchemy models in Jupyter notebook

Is there any way I can import my Flask-SQLAlchemy models into a Jupyter notebook? I would like to be able to explore my models and data in the notebook.
I haven't tried this but I believe it can be done, with a little bit of work.
tl;dr
Import the app, db, and the models you want to use. Push the app context before doing a query. If you understood all this, you're done.
In more detail
In the code which sets up your Flask app, you have a Flask-SQLAlchemy object, which is usually defined something like this:
from flask_sqlalchemy import FlaskSQLAlchemy
db = FlaskSQLAlchemy()
And somewhere else you have your models:
from db_setup import db
class MyThing(db.Model):
thing_id = db.Column(db.Integer())
And further somewhere you have the app:
from flask import Flask
from db_setup import db
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = '...'
db.init_app(app)
Now, in your iPython notebook you have to be able to import the last two pieces above:
from app_setup import app
from models import MyThing
To run a query, you have to be in the app context (see http://flask.pocoo.org/docs/1.0/api/#flask.Flask.app_context):
with app.app_context():
things = MyThing.query.filter(MyThing.thing_id < 100).all()
You should be able to run any query there. If I remember correctly, even outside of the with block the objects in things will still be valid, and you can retrieve their properties, etc.
If you want to explicitly commit, you can import db from where it's defined, and do
db.session.commit()
Just like using the model class name to make a query, db only works inside a context.
Technicalities
Don't worry about this section unless you got the above working but you want to tweak how you did it.
First of all, you might not want to use an app created in exactly the same way that you create it in your Flask code. For example, you might want to use a different config. Instead of importing the module where app is defined, you could just create a new Flask app in your notebook. You still have to import db (to do db.init_app(app)) and MyThing. But these modules probably don't have any configuration code in, since the configuration is all done at the level of the app.
Secondly, instead of use with, you could also explicitly do
my_context = app.app_context()
my_context.push()
then your SQLAlchemy code, and then later
my_context.pop()
This has two advantages. You can just push the context once, before using it in multiple notebook cells. The with block only works inside one cell.
Furthermore, storing the context in a variable after creating it means that you can re-use the same context. For the purposes of SQLAlchemy, the context acts a bit like a transaction. If you make a change to an object in one context, they won't apply in another context, unless you committed to the database. If you store a FlaskSQLAlchemy object in a Python variable, you won't be able to do anything with it inside a different context.
You could also store the context in a variable, then use it in multiple with blocks.
my_context = app.app_context()
with my_context.push():
thing1 = MyThing.query().order_by(MyThing.thing_id).first()
# (Maybe in another cell)
with my_context.push()
print thing1.thing_id
A last consideration, is that it might make sense to define your models using vanilla SQLAlchemy instead of FlaskSQLAlchemy. This would mean that you wouldn't need all the stuff above using contexts, just a database connection to create a session. This would make it much easier to import the models in non-flask code, but the tradeoff would be that it would make using them in Flask a bit harder.

django: need to modify view in installed package

I am using ckeditor in my django project.
I did some code customizing in the view of the package (in ckeditor_uploader).
If I deploy now to the production server I need to include the changes that I did in the package (located in lib/site-packages...).
What would be a good way?
I am seeing only this option:
a) use an editor to modify the installed package on the production server.
Are there any other option that allow me to keep the changed code in my actual project (that is stored and deployed via github) ?
It won't do you any good modifying the package. Instead, you should subclass the view and override the methods you need to behave differently.
from ckeditor_uploader import ImageUploadView
class MyCustomView(ImageUploadView):
def post(self, request, **kwargs):
# do something different here,
# then hand things over to
# the original parent
return super(MyCustomView, self).post(request, **kwargs)

How to properly initialise the flask-sqlalchemy module?

With flask-sqlalchemy, does anyone know why the second approach of construction in http://pythonhosted.org/Flask-SQLAlchemy/api.html doesn't suggest db.app = app as well? It seems the major difference between the first and second construction methods is simply that the first does db.app = app whilst the second does db.app = None
Thanks!
The two methods of initialization are pretty standard for Flask extensions and follow an implicit convention on how extensions are to be initialized. In this section of the Flask documentation you can find a note that explains it:
As you noticed, init_app does not assign app to self. This is intentional! Class based Flask extensions must only store the application on the object when the application was passed to the constructor. This tells the extension: I am not interested in using multiple applications.
When the extension needs to find the current application and it does not have a reference to it, it must either use the current_app context local or change the API in a way that you can pass the application explicitly.
The idea can be summarized as follows:
If you use the SQLAlchemy(app) constructor then the extension will assume that app is the only application, so it will store a reference to it in self.app.
If you use the init_app(app) constructor then the extension will assume that app is one of possibly many applications. So instead of saving a reference it will rely on current_app to locate the application every time it needs it.
The practical difference between the two ways to initialize extensions is that the first format requires the application to exist, because it must be passed in the constructor. The second format allows the db object to be created before the application exists because you pass nothing to the constructor. In this case you postpone the call to db.init_app(app) until you have an application instance. The typical situation in which the creation of the application instance is delayed is if you use the application factory pattern.

Categories

Resources