Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
David Lord
committed
Jun 25, 2013
0 parents
commit 97d224c
Showing
13 changed files
with
283 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
*.pyc | ||
app.db | ||
.idea |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
Basic Flask | ||
=========== | ||
|
||
This sample project shows how I organize a project to use Flask, | ||
Flask-SQLAlchemy, and Alembic together. It demonstrates the application | ||
factory pattern and is organized using blueprints. | ||
|
||
Demonstrating migration generation | ||
---------------------------------- | ||
|
||
I used Alembic to autogenerate a migration and then tweaked the results. If you | ||
want to see autogeneration in action, just delete | ||
`alembic/versions/35b593d48d6a_user_models.py`, then run | ||
`alembic revision --autogenerate -m "user models"`. | ||
|
||
Set up the database | ||
------------------- | ||
|
||
Change `basic_app.config.SQLALCHEMY_DATABASE_URI` to what you want. By default | ||
it points to a sqlite file called `app.db` in the project folder. | ||
|
||
Then run `alembic upgrade head` to set up the database through migrations. | ||
|
||
Or, permform the following from a Python shell. | ||
|
||
In [1]: from basic_app import create_app, db | ||
In [2]: create_app().app_context().push() | ||
In [3]: db.create_all() | ||
|
||
Then run `alembic stamp head` to mark migrations as current. | ||
|
||
Origin | ||
------ | ||
|
||
Created in answer to this question on /r/flask and StackOverflow: | ||
|
||
* [\[AF\] Has anyone ever gotten Alembic to work with Flask Blueprints? \[SQLAlchemy\]](http://www.reddit.com/r/flask/comments/1h1k5g/af_has_anyone_ever_gotten_alembic_to_work_with/) | ||
* [Alembic autogenerates empty Flask-SQLAlchemy migrations](http://stackoverflow.com/questions/17201800/alembic-autogenerates-empty-flask-sqlalchemy-migrations) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
[alembic] | ||
script_location = alembic | ||
|
||
[loggers] | ||
keys = root,sqlalchemy,alembic | ||
|
||
[handlers] | ||
keys = console | ||
|
||
[formatters] | ||
keys = generic | ||
|
||
[logger_root] | ||
level = WARN | ||
handlers = console | ||
qualname = | ||
|
||
[logger_sqlalchemy] | ||
level = WARN | ||
handlers = | ||
qualname = sqlalchemy.engine | ||
|
||
[logger_alembic] | ||
level = INFO | ||
handlers = | ||
qualname = alembic | ||
|
||
[handler_console] | ||
class = StreamHandler | ||
args = (sys.stderr,) | ||
level = NOTSET | ||
formatter = generic | ||
|
||
[formatter_generic] | ||
format = %(levelname)-5.5s [%(name)s] %(message)s | ||
datefmt = %H:%M:%S |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
from logging.config import fileConfig | ||
import os | ||
import sys | ||
from alembic import context | ||
from sqlalchemy import engine_from_config, pool | ||
|
||
sys.path.append(os.getcwd()) | ||
|
||
from basic_app import db, create_app | ||
|
||
config = context.config | ||
|
||
fileConfig(config.config_file_name) | ||
|
||
app = create_app() | ||
config.set_main_option("sqlalchemy.url", app.config["SQLALCHEMY_DATABASE_URI"]) | ||
|
||
target_metadata = db.metadata | ||
|
||
|
||
def run_migrations_offline(): | ||
"""Run migrations in 'offline' mode. | ||
This configures the context with just a URL | ||
and not an Engine, though an Engine is acceptable | ||
here as well. By skipping the Engine creation | ||
we don't even need a DBAPI to be available. | ||
Calls to context.execute() here emit the given string to the | ||
script output. | ||
""" | ||
|
||
url = config.get_main_option("sqlalchemy.url") | ||
context.configure(url=url) | ||
|
||
with context.begin_transaction(): | ||
context.run_migrations() | ||
|
||
|
||
def run_migrations_online(): | ||
"""Run migrations in 'online' mode. | ||
In this scenario we need to create an Engine | ||
and associate a connection with the context. | ||
""" | ||
|
||
engine = engine_from_config( | ||
config.get_section(config.config_ini_section), | ||
prefix='sqlalchemy.', | ||
poolclass=pool.NullPool | ||
) | ||
connection = engine.connect() | ||
context.configure(connection=connection, target_metadata=target_metadata) | ||
|
||
try: | ||
with context.begin_transaction(): | ||
context.run_migrations() | ||
finally: | ||
connection.close() | ||
|
||
if context.is_offline_mode(): | ||
run_migrations_offline() | ||
else: | ||
run_migrations_online() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
"""${message} | ||
|
||
Revision ID: ${up_revision} | ||
Revises: ${down_revision} | ||
Create Date: ${create_date} | ||
""" | ||
|
||
from alembic import op | ||
import sqlalchemy as sa | ||
${imports if imports else ""} | ||
# revision identifiers, used by Alembic. | ||
revision = ${repr(up_revision)} | ||
down_revision = ${repr(down_revision)} | ||
|
||
|
||
def upgrade(): | ||
${upgrades if upgrades else "pass"} | ||
|
||
|
||
def downgrade(): | ||
${downgrades if downgrades else "pass"} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
"""user models | ||
Revision ID: 35b593d48d6a | ||
Revises: None | ||
Create Date: 2013-06-25 10:10:53.866281 | ||
""" | ||
|
||
from alembic import op | ||
import sqlalchemy as sa | ||
from sqlalchemy.sql import expression | ||
|
||
# revision identifiers, used by Alembic. | ||
revision = "35b593d48d6a" | ||
down_revision = None | ||
|
||
|
||
def upgrade(): | ||
op.create_table("group", | ||
sa.Column("id", sa.Integer, primary_key=True), | ||
sa.Column("name", sa.String(100), nullable=False, unique=True, index=True) | ||
) | ||
op.create_table("user", | ||
sa.Column("id", sa.Integer), | ||
sa.Column("username", sa.String(254), nullable=False, unique=True, index=True), | ||
sa.Column("password", sa.String(60)), | ||
sa.Column("name", sa.String(254), nullable=False, server_default=""), | ||
sa.Column("email", sa.String(254), nullable=False, server_default=""), | ||
sa.Column("active", sa.Boolean, nullable=False, server_default=expression.true()), | ||
sa.PrimaryKeyConstraint("id") | ||
) | ||
op.create_table("user_group", | ||
sa.Column("user_id", sa.Integer, sa.ForeignKey("user.id"), primary_key=True), | ||
sa.Column("group_id", sa.Integer, sa.ForeignKey("group.id"), primary_key=True), | ||
) | ||
|
||
|
||
def downgrade(): | ||
op.drop_table("user_group") | ||
op.drop_table("user") | ||
op.drop_table("group") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
from flask import Flask | ||
from flask.ext.script import Manager | ||
from flask.ext.sqlalchemy import SQLAlchemy | ||
from basic_app import config | ||
|
||
db = SQLAlchemy() | ||
|
||
|
||
def load_models(): | ||
from basic_app.auth import models | ||
|
||
load_models() | ||
|
||
|
||
def init_extensions(app): | ||
db.init_app(app) | ||
|
||
|
||
def init_views(app): | ||
from basic_app import auth | ||
|
||
app.register_blueprint(auth.bp, url_prefix="/auth") | ||
|
||
|
||
def create_app(config=config): | ||
app = Flask(__name__) | ||
app.config.from_object(config) | ||
|
||
init_extensions(app) | ||
|
||
return app | ||
|
||
manager = Manager(create_app) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
from flask import Blueprint | ||
|
||
bp = Blueprint("auth", __name__, template_folder="templates") | ||
|
||
from basic_app.auth import views |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
from sqlalchemy.sql import expression | ||
from basic_app import db | ||
|
||
|
||
class Group(db.Model): | ||
id = db.Column(db.Integer, primary_key=True) | ||
name = db.Column(db.String(100), nullable=False, unique=True, index=True) | ||
|
||
|
||
class User(db.Model): | ||
id = db.Column(db.Integer, primary_key=True) | ||
username = db.Column(db.String(254), nullable=False, unique=True, index=True) | ||
password = db.Column(db.String(60)) | ||
name = db.Column(db.String(254), nullable=False, default="", server_default="") | ||
email = db.Column(db.String(254), nullable=False, default="", server_default="") | ||
active = db.Column(db.Boolean, nullable=False, default=False, server_default=expression.true()) | ||
|
||
groups = db.relationship(Group, lambda: user_group, backref=db.backref("users")) | ||
|
||
user_group = db.Table("user_group", | ||
db.Column("user_id", db.Integer, db.ForeignKey(User.id), primary_key=True), | ||
db.Column("group_id", db.Integer, db.ForeignKey(Group.id), primary_key=True) | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
from basic_app.auth import bp | ||
from basic_app.auth.models import User | ||
|
||
|
||
@bp.route("/<username>") | ||
def hello(username): | ||
u = User.query.filter_by(username=username).first_or_404() | ||
return "Hello, {}!".format(u.username) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
DEBUG = True | ||
SECRET_KEY = "dev" | ||
|
||
SQLALCHEMY_DATABASE_URI = "sqlite:///app.db" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
from basic_app import manager | ||
|
||
manager.run() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
Flask-Script | ||
Flask-SQLAlchemy | ||
alembic |