I'm building a large, complex Flask application. It has lots of route functions (which need to do database calls) and lots of services (which also need to do database calls).
I'm using flask_sqlalchemy to do the database calls in the route functions as normal with model syntax (User.query).
I would also like to make database calls in the services. However, I can't do this without setting an app context:
with app.app_context():
User.query
which requires importing the app, which leads to circular imports (because the app imports the routes, which import the services, which have to import the app).
QUESTION 1: Do you know a way to get round this circular import problem?
Another approach could be to use flask_sqlalchemy in the routes and sqlalchemy in the services. This means nothing needs to be shared except for the database url and.... the models.
QUESTION 2: Do you know a way to use the same model files with both flask_sqlalchemy and normal sqlalchemy?
I've tried this: https://dev.to/nestedsoftware/flask-and-sqlalchemy-without-the-flask-sqlalchemy-extension-3cf8
...however it breaks my relationships.
I am following the flask app pattern shown here: https://github.com/sloria/cookiecutter-flask/blob/master/%7B%7Bcookiecutter.app_name%7D%7D/README.rst (application factory)
Thanks,
Louise
Related
I would like to exchange data between two django apps that are coming from a single big app that due to the increasing size and functionalities we decided to split.
Specifically I need to retrive only a string in one app from the other. Litterally a 10 character string.
The only thing that I found at the moment that satisfies me, since I would like to avoid import stuff from the other app (to me it seems not a clean way to do it, in the other case please change my mind), is making an http request from one app to the other.
Anyway I found it overkill.
Is there a clean way to achive this without using http request or imports?
If you mean constant app configuration data, that lives in the project settings.py adnd doesn't change except at a server re-start
from django.conf import settings
more
It's possible to make an import fail soft, if you just want to handle the case where the other app is not installed. For example
try:
from other_app.models import Foo
except ModuleNotFoundError:
from .models import Foo_Stub as Foo
(obviously you can get as sophisticated as you want with your stub models and other methods that aren't available from the other app).
I want to use redis-py directly to work with flask, instead of other wrapper lib (e.g. flask-redis, flask-and-redis) of flask plugins. How to initialize redis-client in factory function create_app() of flask application ? Or how to properly just initialize redis.StrictRedis (maybe not compatible with other flask plugins of redis ??) ? Because there're some operations related to token persistence in router of other modules using this redis.StrictRedis object.
Any advice, please ?
Interesting question, I think using the wrappers may make things easier but if you just want to use redis as a cache you can very easily import redis and just create/instantiate alongside the flask app.
import redis
from flask import Flask
# make redis
redis_cache = redis.StrictRedis()
# make flask app
app = Flask(__name__)
# business logic
#app.route('/<string:item>')
def index(item):
# if cache hit then get from redis
if redis_cache.exists(item):
value = redis_cache.get(item)
# cache miss
else:
value = 'Not in cache'
return value
This is the simplest way.
You can also follow this link to create the setup function and add the redis instantiation in the create_app function.
I didn't get it clearly from Flask docs. Also, I can see similar stackoverflow questions but I still didn't get my answer, hence asking.
I have a flask application served using gunicorn+gevent. Gunicorn worker process, on start, creates a Flask application. Then it imports some files that setup a few global things, like a udp connection to a statsd server, etc. The setup needs to be done only once i.e. on worker process start and not with every client request. The setup code in the imported files needs access to config variables.
I know that while serving a request I can use the current_app proxy, but not outside a request.
One way can be: put Flask app creation code in a separate file and include it wherever you need access to config.
Ex:
file: mywsgi.py
from flask import Flask
application = Flask(__name__)
application.config.from_pyfile('myconfig.cfg')
file: mygunicornapp.py
from mywsgi import application
import file1
import file2
# import more files
file: file1.py
from mywsgi import application
# use the application config to setup something
file: file2.py
from mywsgi import application
# use the application config to setup something
Is this the preferred way?
Flask doc says I can create application context explicitly.
Can I push application context, just after creating my flask app, and never pop it. So that the application context is always there as long as my process runs and the current_app proxy will be available application wide even when no request being served?
Ex:
from flask import Flask
application = Flask(__name__)
application.config.from_pyfile('myconfig.cfg')
application.app_context().push()
Now I should be able to use the current_app proxy anywhere in my code. Thoughts, please!
== Update ==
The files file1.py, file2.py etc are imported for adding routes to the application. They provide the functions that handle my api requests. So the file mygunicornapp.py looks more like:
file: mygunicornapp.py
from mywsgi import application
from file1 import API1
#application.route("/api1")
def handle_api1():
return API1.handler()
from file2 import API2
#application.route("/api2")
def handle_api2():
return API2.handler()
# many more routes
Now file1 imports many other files and they, in turn, import many more files. Any of these imported files may need access to a config parameter that I have set on the application object. The question is: How do I make the application object available to all these files? Do you suggest that I pass the application object to each file?
Is it possible to just delay adding routes? I mean set routes after current_app context local is available. That means the files will be imported after current_app is available. I tried adding routes to the current_app context local in 'before_first_request' callback. The problem with that is, the very first request returns 404. Subsequent returns give a correct response.
Why don't you make functions in file1 and file2, and pass the argument app into them? Then you can call these functions in your setup code in mywsgi.py, using as an argument the app object you just created.
This should work much better than some of the other things you suggested. The different files importing each other is close to a circular import. Pushing an app context is also something that leaves you likely to end up with difficult to understand bugs.
If you create the object app in one file and import it from that file everywhere, you basically have a global variable (using a namespace). This is going to cause problem when you want to test your app setup code, or create more than one version of your app for another reason. There is also the issue that you won't be able to import any of file1, file2 without creating an app object. While testing these, or possibly re-using some of that code outside of Flask, this will be a pain.
It's much better to create the app object once and pass it around. Having a function which returns the newly created app, which can be imported and called from anywhere, is a common way of organizing a flask app. This file is often called factory.py. It makes it easier to create zero, one or more copies of the app, rather than making it more difficult.
My Flask app should execute some rather complicated sql queries, parse them and display results. Now I'm using SQLAlchemy (as described here), but I want to switch to Records, simple wrapper over SQLAlchemy (it has all I need out of the box). I haven't found any examples of integration Records into Flask.
Can you provide an example of simple Flask app with vanilla Records integration?
Records handle the SQLAlchemy connection lifecycle, I don't think it is a good idea to really integrate them. You can share the config, passing the database URL to records.Database.
app = Flask(__name__)
app.config['DATABASE_URL'] = 'postgres://...'
records_db = records.Database(app.config['DATABASE_URL'])
If you use Flask-SQLAlchemy, the config key is SQLALCHEMY_DATABASE_URI.
Add the records_db to Flask context g to access it from any file with a Flask context, without messing with circular imports.
from flask import g
g.records = records_db
I will be brief: to work in the spirit and idea of a Django app, it is ok for an app to import models from inside another app ? Say, a User statistics app will import models from a User app something like: from users.models import users
The answer is yes. It's perfectly okay for one application inside your django project to import models from another application. The power of a django project lies in the apps and their interactions.
Also make sure that you have utility applications importing models from more generic applications and not the other way. So "userstatistics" app should import models from the "users" app but "users" app should not rely on the "userstatistics".
If your app is importing models from a 3rd party application (lets say django-piston), be sure to specify that in a requirements file.
If you're building an internal app that has no chance of ever being released to the public, sure, do whatever you want.
If you're building an internal app that has little chance of ever being released to the public, but will possibly be used by future/current developers, sure, but be sure to document what the app needs to work properly.
If you're building an app for public release, try to keep it self-dependent (and django-internals dependent, ie, use what django provides, when possible). If you really need a third-party app to work, or if a third party app would make your code more manageable, then sure, include dependencies, but be doubly sure to document all requirements and necessary setup.
In most cases, you can do almost whatever you want so long as you have sufficient documentation.
I do, however, have to question the sanity of making your own User model that has the same name as django's builtin auth.User.
You cand try better extending the Django User model with inheritance. You will use the django user with custom field added, so you will have the same user for all the apps.
You can directly import models in app2/models.py. Usually you might need a foreign key, which looks like
models.ForeignKey('app1.ModelClass1', on_delete=models.CASCADE, related_name='modelclass2')
Don't do this. They will have the same app name and the ORM will be confused. Use an abstract model instead, and have both derive from it.