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.
Related
I'm a relatively new python user, coming from the .NET world.
I'm working on a web application with a python backend (using Flask and SQLAlchemy), where the db models are defined using SQLAlchemy and now I'm writing my first function where I want to retrieve data from the database and bring to the frontend.
Here is a non-functional example (since SQLAlchemy cannot be jsonified directly) just to show what I want to do:
#app.route('/validationrules', methods=["GET"])
#login_required
def getValidationRules():
return jsonify(db.session.query(ValidationRules).all())
My question is, is it customary to create view models when using the stack I mentioned above, and use those to create a bridge between the SQLAlchemy and json? Or do I just create a custom dict in every method and jsonify that?
Some search results also suggested that I create a base model with a to_dict method, and have all my database models inherit from that, but that seems a bit too coupled to me.
What are the best practices for a case like this?
UPDATE: Following this answer I would now change my answer to use marshmallow / marshmallow-sqlalchemy.
Previous answer:
I don't know the answer for certain but...
From Miguel Grinberg's Flask Web Development 2nd edition, page 210-213 the approach he uses is to have a method
def Post(db.Model):
# ...
def to_json(self):
json_post = {
** json using model **
}
return json_post
defined in the models.py
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'
],
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.
My Django app has several apps, each with their own models.py. I also have an api app which provides a REST API.
For model A, I often wanted to get data paginated a certain way (the data-tables way). I wanted to do this in a few places (inside the api app and some main UI apps), so I created a custom object manager PaginationManager and attached it to model A. Then
Life was good and DRY, but now another model B needs to be gotten in a paginated way. I would like to use the same PaginationManager, but which app should it go in? Does it belong outside of any app? It seems like a lot of business logic to be putting in a util folder or something.
Best practice would be to make it as general as possible and extract it into a lib or utils app that can be reused by all of your apps.
I typically will have a utils app that contains thinks like paginators.py, serializers.py, mixins.py and so on. Usually the more generic and reusable the better.
In trying to save as much time as possible in my development and make as many of my apps as reusable as possible, I have run into a bit of a roadblock. In one site I have a blog app and a news app, which are largely identical, and obviously it would be easier if I could make a single app and extend it where necessary, and then have it function as two separate apps with separate databases, etc.
To clarify, consider the following: hypothetically speaking, I would like to have a single, generic news_content app, containing all the relevant models, views, url structure and templatetags, which I could then include and extend where necessary as many times as I like into a single project.
It breaks down as follows:
news_content/
templatetags/
__init__.py
news_content.py
__init__.py
models.py (defines generic models - news_item, category, etc.)
views.py (generic views for news, archiving, etc.)
urls.py
admin.py
Is there a way to include this app multiple times in a project under various names? I feel like it should be obvious and I'm just not thinking clearly about it. Does anybody have any experience with this?
I'd appreciate any advice people can give. Thank you.
What's the actual difference between blogs and news? Perhaps that difference ought to be part of the blog/news app and you include it just once.
If you have a blog page with blog entries and a news page with news entries and the only difference is a field in the database (kind_of_item = "blog" vs. kind_of_item = "news") then perhaps have you have this.
urls.py
(r'^/(?P<kind>blog)/$', 'view.stuff'),
(r'^/(?P<kind>news)/$', 'view.stuff'),
views.py
def stuff( request, kind ):
content= news_blog.objects.filter( kind=kind )
return render_to_response( kind+"_page", { 'content': content } )
Perhaps you don't need the same app twice, but need to extend the app to handle both use cases.
In this case you could create the common piece of code as a Python module instead of a whole new application.
Then for each instance you would like to use it, create an app and import the bits from that module.
I'm not 100% sure I understand your question, so I'm going to list my understanding, and let me know if it is different from yours.
You want to have a "news" and a "blog" section of your website with identical functionality.
You want to have "news" and "blog" entries stored separately in the database so they don't end up intermingling.
If this is the case, I'd suggest making an API to your views. Something like this:
views.py:
def view_article(request, article_slug,
template_name='view_article.html',
form_class=CommentForm,
model_class=NewsArticle,
success_url=None,
):
urls.py:
(r'^news/(?P<article_slug>[-\w]+)/$', 'view_article', {}, "view_news_article"),
(r'^blog/(?P<article_slug>[-\w]+)/$', 'view_article', {'model_class': BlogArticle}, "view_blog_article"),
This makes your app highly reusable by offering the ability to override the template, form, model, and success_url straight from urls.py.