Using Flask-SQLAlchemy in Blueprint Models without an Application Link

I am trying to create a “modular application” in Flask using Blueprints.

When creating models, however, I encounter the problem of accessing the application to get the db object provided by Flask-SQLAlchemy. I would like to be able to use some drawings with multiple applications (similar to how Django applications can be used), so this is not a good solution. *

  • You can make switcharoo and create Blueprint to create a db instance that the application then imports along with the rest of the drawing. But then any other project that wants to create models should import from this project instead of the application.

My questions are as follows:

  • Is there a way for Blueprints to define models without any knowledge of the application they will use later - and are there several drawings together? By this I mean the need to import the application module / package from your Blueprint.
  • Am I wrong from the start? Are the drawings non-application independent and not distributed (la Django applications)?
    • If not, which template should be used to create something like this? Jar extensions? If you just don’t do this - and perhaps centralize all à la Ruby on Rails models / schemes?

Edit: I already thought about it myself, and it could be more related to SQLAlchemy than to Flask, because when declaring models you need to have declarative_base() . And it must happen from somewhere, anyway!

Perhaps the best solution is to define a project diagram in one place and distribute it, as Ruby on Rails does. SQLAlchemy's declarative class definitions are really more like schema.rb than Django models.py. I suggest that this would also facilitate the use of migrations (from alembic or sqlalchemy-migrate ).




I was asked to give an example, so let's do something simple: let's say I have a plan that describes "flatpages" - simple, "static" content stored in a database. It uses a table with a simple name (for URLs), a title and a body. This is simple_pages/__init__.py :

 from flask import Blueprint, render_template from .models import Page flat_pages = Blueprint('flat_pages', __name__, template_folder='templates') @flat_pages.route('/<page>') def show(page): page_object = Page.query.filter_by(name=page).first() return render_template('pages/{}.html'.format(page), page=page_object) 

Then it would be nice to let this scheme define its own model (this is in simple_page/models.py ):

 # TODO Somehow get ahold of a `db` instance without referencing the app # I might get used in! class Page(db.Model): name = db.Column(db.String(255), primary_key=True) title = db.Column(db.String(255)) content = db.Column(db.String(255)) def __init__(self, name, title, content): self.name = name self.title = title self.content = content 



This question is related to:

  • Flask-SQLAlchemy Import / Context
  • What is your module layout folder for a Flask application?

And others, but all of the answers, seem to rely on importing the app db instance or the opposite. The Big App Like page of the wiki page also uses the import your app into your plan template.

* Since the official documentation shows how to create routes, views, templates and assets in Blueprint without worrying about which application it is “included”, I suggested that Blueprints should, in general, be reusable in applications, However, this modularity is not seems useful without independent models.

Since Blueprints can be connected to the application more than once, maybe this is the wrong approach to the model in the Drawings?

+48
python design flask flask-sqlalchemy
Oct 24 '12 at 22:28
source share
4 answers

I believe the surest answer is that modular drawings should not directly relate to data access, but instead rely on an application that provides a compatible implementation.

So, considering your sample project.

 from flask import current_app, Blueprint, render_template flat_pages = Blueprint('flat_pages', __name__, template_folder='templates') @flat_pages.record def record(state): db = state.app.config.get("flat_pages.db") if db is None: raise Exception("This blueprint expects you to provide " "database access through flat_pages.db") @flat_pages.route('/<page>') def show(page): db = current_app.config["flat_pages.db"] page_object = db.find_page_by_name(page) return render_template('pages/{}.html'.format(page), page=page_object) 

From this, nothing prevents you from providing a default implementation.

 def setup_default_flat_pages_db(db): class Page(db.Model): name = db.Column(db.String(255), primary_key=True) title = db.Column(db.String(255)) content = db.Column(db.String(255)) def __init__(self, name, title, content): self.name = name self.title = title self.content = content class FlatPagesDBO(object): def find_page_by_name(self, name): return Page.query.filter_by(name=name).first() return FlatPagesDBO() 

And in your configuration.

 app.config["flat_pages.db"] = setup_default_flat_pages_db(db) 

The above can be made cleaner without relying on direct inheritance from db.Model and instead just use the vanial declarative_base from sqlalchemy, but that should be the gist of it.

+25
Nov 17 '12 at 16:22
source share

Drawings are a logical separation of problems rather than actual applications.

The database instance must be configured by the application, not Blueprint, so that you can configure settings such as background processing and other modules in one place. If Blueprint sets up the database, it will depend on the rest of the Flask application, making it less modular.

Take a look at https://github.com/masom/Bluemonk for a medium-sized flag application using many different Flask plugins and design patterns.

+8
Nov 13 '12 at 16:46
source share

You asked: "Are the drawings non-application independent and can be distributed (la Django applications)?"

The answer is yes. The drawings are not similar to the Django application.

If you want to use different applications / configurations, you need to use the "Application Manager", not the drawings. Read this [1]: http://flask.pocoo.org/docs/patterns/appdispatch/#app-dispatch [1]

Also, the link is here [1] http://flask.pocoo.org/docs/blueprints/#the-concept-of-blueprints [1]

It is clearly stated in it, and I quote: “The plan in Flask is not a plug-in application, because in fact it is not an application - its set of operations that can be registered in the application, even several times. Why not have several application objects you can do this (see "Application Manager"), but your applications will have separate configurations and will be managed at the WSGI level. "

+1
Oct 25
source share

I have similar needs for creating drawings that are fully modular and have no reference to the application. I may have come up with a clean solution, but I'm not sure how right he is and what his limitations are.

The idea is to create a separate db object ( db = SQLAlchemy() ) inside the drawing and call the init_app() and create_all() methods from which the root application is created.

Here is an example code to show how the project is structured: The application is called jobs , and the drawing is called status , and it is stored inside the drawings folder.

blueprints.status.models.py

 from flask_sqlalchemy import SQLAlchemy db = SQLAlchemy() # <--- The db object belonging to the blueprint class Status(db.Model): __tablename__ = 'status' id = db.Column(db.Integer, primary_key=True) job_id = db.Column(db.Integer) status = db.Column(db.String(120)) 

models.py

 from flask_sqlalchemy import SQLAlchemy db = SQLAlchemy() # <--- The db object belonging to the root app class Job(db.Model): __tablename__ = 'job' id = db.Column(db.Integer, primary_key=True) state = db.Column(db.String(120) 

factory.py

 from .blueprints.status.models import db as status_db # blueprint db from .blueprints.status.routes import status_handler # blueprint handler from .models import db as root_db # root db from flask import Flask def create_app(): app = Flask(__name__) # Create database resources. app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////path/to/app.db' root_db.init_app(app) status_db.init_app(app) # <--- Init blueprint db object. with app.app_context(): root_db.create_all() status_db.create_all() # <--- Create blueprint db. # Register blueprint routes. app.register_blueprint(status_handler, url_prefix="/status") return app 

I tested it with gunicorn with a gevent working, and it works. I asked a separate question about the reliability of the solution here: Create one instance of SQLAlchemy for each project and call create_all several times

0
Dec 24 '17 at 23:29
source share



All Articles