On Github jasonamyers / filling-the-flask
Created by Jason A Myers / @jasonamyers
I have two files setup: flaskfilled/__init__.py and config.py
from flask import Flask from config import config def create_app(config_name): app = Flask(__name__) app.config.from_object(config[config_name]) return app
import os basedir = os.path.abspath(os.path.dirname(__file__)) class Config: SECRET_KEY = 'development key' ADMINS = frozenset(['jason@jasonamyers.com', ]) class DevelopmentConfig(Config): DEBUG = True config = { 'development': DevelopmentConfig, 'default': DevelopmentConfig }
Commands for running a development server, a customised Python shell, etc
pip install flask-script
#! /usr/bin/env python import os from flask.ext.script import Manager from flaskfilled import create_app app = create_app(os.getenv('FLASK_CONFIG') or 'default') manager = Manager(app) if __name__ == '__main__': manager.run()
from flask.ext.script import Shell def make_shell_context(): return dict(app=app) manager.add_command('shell', Shell(make_context=make_shell_context))
$ python manage.py usage: manage.py [-?] {runserver,shell} ... positional arguments: {runserver,shell} runserver Runs the Flask development server i.e. app.run() shell Runs a Python shell inside Flask application context. optional arguments: -?, --help show this help message and exit
$ python manage.py shell In [1]: app.config['DEBUG'] Out[1]: True
pip install flask-sqlalchemy
from flask.ext.sqlalchemy import SQLAlchemy db = SQLAlchemy() def create_app(config_name): app = Flask(__name__) app.config.from_object(config[config_name]) db.init_app(app) return app
class DevelopmentConfig(Config): DEBUG = True SQLALCHEMY_DATABASE_URI = "sqlite:////tmp/dev.db"
from flaskfilled import db class Cookie(db.Model): __tablename__ = 'cookies' cookie_id = db.Column(db.Integer(), primary_key=True) cookie_name = db.Column(db.String(50), index=True) cookie_recipe_url = db.Column(db.String(255)) quantity = db.Column(db.Integer())
from flask.ext.script import Command from flaskfilled import db from flaskfilled.models import Cookies def make_shell_context(): return dict(app=app, db=db) class DevDbInit(Command): '''Creates database tables from sqlalchemy models''' def __init__(self, db): self.db = db def run(self): self.db.create_all()
$ python manage.py db_init $ python manage.py shell In [1]: db.metadata.tables Out[1]: immutabledict({'cookies': Table('cookies', 'stuff')}) In [2]: from flaskfilled.models import Cookie
c = Cookie(cookie_name="Chocolate Chip", cookie_recipe_url="http://zenofthecookie.com/chocolatechip.html", quantity=2) db.session.add(c) db.session.commit()
Ties Alembic into flask-script!
pip install flask-migrate
from flask.ext.migrate import Migrate, MigrateCommand migrate = Migrate(app, db) manager.add_command('db', MigrateCommand)
$ python manage.py db init
$ python manage.py db migrate -m "initial migration" INFO [alembic.migration] Context impl SQLiteImpl. INFO [alembic.migration] Will assume non-transactional DDL. Generating flask-filled/migrations/versions/586131216f6_initial_migration.py ... done
$ python manage.py db upgrade INFO [alembic.migration] Context impl SQLiteImpl. INFO [alembic.migration] Will assume non-transactional DDL. INFO [alembic.migration] Running upgrade -> 586131216f6, initial migration
pip install flask-login
from flask.ext.login import LoginManager login_manager = LoginManager() def create_app(config_name): app = Flask(__name__) app.config.from_object(config[config_name]) db.init_app(app) login_manager.setup_app(app) from .main import main as main_blueprint app.register_blueprint(main_blueprint) from .auth import auth as auth_blueprint app.register_blueprint(auth_blueprint, url_prefix='/auth') return app
from werkzeug.security import generate_password_hash, check_password_hash from flaskfilled import login_manager class User(db.Model, UserMixin): __tablename__ = 'users' id = db.Column(db.Integer(), primary_key=True) username = db.Column(db.String, primary_key=True) password = db.Column(db.String) authenticated = db.Column(db.Boolean, default=False)
def is_active(self): return True def get_id(self): return self.id def is_authenticated(self): return self.authenticated def is_anonymous(self): return False
@property def password(self): raise AttributeError('password is not a readable attribute') @password.setter def password(self, password): self.password_hash = generate_password_hash(password) def verify_password(self, password): return check_password_hash(self.password_hash, password)
from flask import Blueprint auth = Blueprint('auth', __name__) from . import views
from flask import render_template, redirect, request, url_for, flash from flask.ext.login import login_user, logout_user, login_required from . import auth from flaskfilled.models import User
@auth.route('/login', methods=['GET', 'POST']) def login(): if request.method == 'POST': username = request.form.get('username', '') password = request.form.get('password', '') user = User.query.filter_by(username=username).first() if user is not None and user.verify_password(password): login_user(user) next = request.args.get('next') return redirect(next or url_for('main.index')) else: flash('Wrong username or password.') return render_template('auth/login.html')
@auth.route('/logout') @login_required def logout(): logout_user() flash('You have been logged out.') return redirect(url_for('main.index'))
{% extends "base.html" %} {% block title %}Login{% endblock %} {% block page_content %} <div class="page-header"> <h1>Login</h1> </div> <div class="col-md-4"> <form action=""> Username: <input type="text" name="username"><br> Password: <input type="password" name="password"><br> <input type="submit"> </form> <br> <p>Forgot your password? <a href="{{ url_for('auth.password_reset_request') }}">Click here to reset it</a>.</p> <p>New user? <a href="{{ url_for('auth.register') }}">Click here to register</a>.</p> </div> {% endblock %}
from flask import render_template from . import main @main.route('/', methods=['GET']) def index(): return render_template('main/index.html')
{% extends "base.html" %} {% block title %}The Index{% endblock %} {% block page_content %} {% if not current_user.is_authenticated() %} <p><a href="{{ url_for('auth.login') }}">Click here to login</a>.</p> {% else %} <p><a href="{{ url_for('auth.logout') }}">Click here to logout</a>.</p> {% endif %} {% endblock %}
$ python manage.py db migrate -m "User" Generating /Users/jasonamyers/dev/flask-filled/migrations/versions/8d9327f04f_user.py ... done $ python manage.py db upgrade INFO [alembic.migration] Running upgrade 586131216f6 -> 8d9327f04f, User
$ python manage.py runserver
pip install flask-wtf
from flask.ext.wtf import Form from wtforms import StringField, PasswordField, SubmitField from wtforms.validators import Required, Length class LoginForm(Form): username = StringField('username', validators=[Required(), Length(1, 64)]) password = PasswordField('Password', validators=[Required()]) submit = SubmitField('Log In')
@auth.route('/login', methods=['GET', 'POST']) def login(): form = LoginForm() if form.validate_on_submit(): user = User.query.filter_by(username=form.username.data).first() if user is not None and user.verify_password(form.password.data): login_user(user) next = request.args.get('next') return redirect(next or url_for('main.index')) else: flash('Wrong username or password.') return render_template('auth/login.html', form=form)
{% block page_content %} <div class="col-md-4"> <form action="" method="POST"> {{ form.csrf_token }} {% if form.csrf_token.errors %} <div class="warning">You have submitted an invalid CSRF token</div> {% endif %} {{form.username.label }}: {{ form.username }} {% if form.username.errors %} {% for error in form.username.errors %} {{ error }} {% endfor %} {% endif %}<br> {{form.password.label }}: {{ form.password }} {% if form.password.errors %} {% for error in form.password.errors %} {{ error }} {% endfor %} {% endif %}<br> {{ form.submit }} </form> <br> </div>
pip install flask-principal
from flask.ext.principal import Principal principal = Principal() def create_app(config_name): principal.init_app(app)
roles_users = db.Table('roles_users', db.Column('user_id', db.Integer(), db.ForeignKey('users.user_id')), db.Column('role_id', db.Integer(), db.ForeignKey('roles.id'))) class Role(db.Model): __tablename__ = 'roles' id = db.Column(db.Integer(), primary_key=True) name = db.Column(db.String(80), unique=True) description = db.Column(db.String(255))
class User(db.Model, UserMixin): roles = db.relationship('Role', secondary=roles_users, primaryjoin=user_id == roles_users.c.user_id, backref='users')
@identity_loaded.connect def on_identity_loaded(sender, identity): # Set the identity user object identity.user = current_user # Add the UserNeed to the identity if hasattr(current_user, 'id'): identity.provides.add(UserNeed(current_user.id)) # Assuming the User model has a list of roles, update the # identity with the roles that the user provides if hasattr(current_user, 'roles'): for role in current_user.roles: identity.provides.add(RoleNeed(role.name))
from flask import current_app from flask.ext.principal import identity_changed, Identity @auth.route('/login', methods=['GET', 'POST']) def login(): form = LoginForm() if form.validate_on_submit(): user = User.query.filter_by(username=form.username.data).first() if user is not None and user.verify_password(form.password.data): login_user(user) identity_changed.send(current_app._get_current_object(), identity=Identity(user.user_id)) next = request.args.get('next') return redirect(next or url_for('main.index')) else: flash('Wrong username or password.') return render_template('auth/login.html', form=form)
from flask.ext.principal import Permission, RoleNeed admin_permission = Permission(RoleNeed('admin'))
from flaskfilled.auth import admin_permission @main.route('/settings', methods=['GET']) @admin_permission.require() def settings(): return render_template('main/settings.html')
from flask.ext.mail import Mail mail = Mail() def create_app(config_name): mail.init_app(app)
from flask.ext.mail import Mail mail = Mail() def create_app(config_name): mail.init_app(app)
from flask_mail import Message @main.route('/mailme', methods=['GET']) def mail(): msg = Message('COOKIES!', sender='from@example.com', recipients=['to@example.com']) msg.body = 'There all mine!' msg.html = '<b>There all mine!</b>' mail.send(msg)
https://github.com/humiaozuzu/awesome-flask
Jason Myers / @jasonamyers / Essential SQLAlchemy