diff --git a/.gitignore b/.gitignore index f2ae0c1..7ec5563 100644 --- a/.gitignore +++ b/.gitignore @@ -42,4 +42,6 @@ output/*/index.html docs/_build # Cookiecutter -output/ \ No newline at end of file +output/ + +myflaskapp/ diff --git a/README.rst b/README.rst index 7c5d5bb..90f5e4e 100644 --- a/README.rst +++ b/README.rst @@ -12,7 +12,7 @@ Features - Flask-SQLAlchemy with basic User model - Flask-WTForms with login and registration forms - Procfile for deploying to a PaaS (e.g. Heroku) -- nose for testing +- Flask-Testing and nose for testing - A simple ``manage.py`` script. - CSS and JS minification using Flask-Assets - Easily switch between development and production environments through the MYFLASKAPP_ENV system variable. @@ -61,6 +61,13 @@ BSD licensed. Changelog --------- +0.3.0 +***** + +- More "divisional" organization: each blueprint contains its own view, models, and forms in a directory. There is still a single directory for templates and static assets. +- Use Flask-Bcrypt for password hashing. +- Flask-Testing support. + 0.2.0 (09/21/2013) ****************** - Add manage.py script diff --git a/{{cookiecutter.repo_name}}/Procfile b/{{cookiecutter.repo_name}}/Procfile index b5c65bd..7f3d32e 100644 --- a/{{cookiecutter.repo_name}}/Procfile +++ b/{{cookiecutter.repo_name}}/Procfile @@ -1 +1 @@ -web: gunicorn {{cookiecutter.repo_name}}.main:app -b 0.0.0.0:$PORT -w 3 +web: gunicorn {{cookiecutter.repo_name}}.app:create_app\(\) -b 0.0.0.0:$PORT -w 3 diff --git a/{{cookiecutter.repo_name}}/manage.py b/{{cookiecutter.repo_name}}/manage.py index 57a7b66..3979f89 100644 --- a/{{cookiecutter.repo_name}}/manage.py +++ b/{{cookiecutter.repo_name}}/manage.py @@ -4,22 +4,21 @@ import os import sys import subprocess from flask.ext.script import Manager, Shell, Server -from {{cookiecutter.repo_name }} import models from {{cookiecutter.repo_name }}.app import create_app -from {{cookiecutter.repo_name}}.models import db +from {{cookiecutter.repo_name}}.settings import DevConfig +from {{cookiecutter.repo_name}}.database import db -env = os.environ.get("{{cookiecutter.repo_name | upper }}_ENV", 'prod') -app = create_app("{{cookiecutter.repo_name}}.settings.{0}Config" - .format(env.capitalize())) + +app = create_app(DevConfig) manager = Manager(app) TEST_CMD = "nosetests" def _make_context(): '''Return context dict for a shell session so you can access - app, db, and models by default. + app and db by default. ''' - return {'app': app, 'db': db, 'models': models} + return {'app': app, 'db': db} @manager.command def test(): @@ -32,7 +31,7 @@ def createdb(): '''Create a database from the tables defined in models.py.''' db.create_all() -manager.add_command("runserver", Server()) +manager.add_command("server", Server()) manager.add_command("shell", Shell(make_context=_make_context)) if __name__ == '__main__': diff --git a/{{cookiecutter.repo_name}}/{{cookiecutter.repo_name}}/app.py b/{{cookiecutter.repo_name}}/{{cookiecutter.repo_name}}/app.py index feca3fd..a4e8637 100644 --- a/{{cookiecutter.repo_name}}/{{cookiecutter.repo_name}}/app.py +++ b/{{cookiecutter.repo_name}}/{{cookiecutter.repo_name}}/app.py @@ -5,12 +5,14 @@ from flask.ext.sqlalchemy import SQLAlchemy from flask.ext.assets import Environment from webassets.loaders import PythonLoader +from {{ cookiecutter.repo_name }}.settings import ProdConfig from {{cookiecutter.repo_name}} import assets -from {{cookiecutter.repo_name}}.models import db +from {{cookiecutter.repo_name}}.database import db +from {{cookiecutter.repo_name}} import public, user assets_env = Environment() -def create_app(config_object): +def create_app(config_object=ProdConfig): '''An application factory, as explained here: http://flask.pocoo.org/docs/patterns/appfactories/ @@ -25,8 +27,12 @@ def create_app(config_object): assets_loader = PythonLoader(assets) for name, bundle in assets_loader.load_bundles().iteritems(): assets_env.register(name, bundle) + register_blueprints(app) + return app + + +def register_blueprints(app): # Register blueprints - from {{cookiecutter.repo_name}}.modules import public, member - app.register_blueprint(public.blueprint) - app.register_blueprint(member.blueprint) + app.register_blueprint(public.views.blueprint) + app.register_blueprint(user.views.blueprint) return app diff --git a/{{cookiecutter.repo_name}}/{{cookiecutter.repo_name}}/database.py b/{{cookiecutter.repo_name}}/{{cookiecutter.repo_name}}/database.py new file mode 100644 index 0000000..c1ffd95 --- /dev/null +++ b/{{cookiecutter.repo_name}}/{{cookiecutter.repo_name}}/database.py @@ -0,0 +1,8 @@ +# -*- coding: utf-8 -*- +'''Database module, including the SQLAlchemy database object and DB-related +mixins. +''' + +from flask.ext.sqlalchemy import SQLAlchemy + +db = SQLAlchemy() diff --git a/{{cookiecutter.repo_name}}/{{cookiecutter.repo_name}}/main.py b/{{cookiecutter.repo_name}}/{{cookiecutter.repo_name}}/main.py deleted file mode 100644 index d6c2778..0000000 --- a/{{cookiecutter.repo_name}}/{{cookiecutter.repo_name}}/main.py +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -""" -Entry point for all things, to avoid circular imports. -""" -import os -from .app import create_app -from .models import User, db -import {{cookiecutter.repo_name}}.modules as modules - -if __name__ == '__main__': - # Get the environment setting from the system environment variable - env = os.environ.get("{{cookiecutter.repo_name | upper}}_ENV", "prod") - app = create_app("{{cookiecutter.repo_name}}.settings.{env}Config" - .format(env=env.capitalize())) diff --git a/{{cookiecutter.repo_name}}/{{cookiecutter.repo_name}}/modules/__init__.py b/{{cookiecutter.repo_name}}/{{cookiecutter.repo_name}}/modules/__init__.py deleted file mode 100644 index 33bdd6a..0000000 --- a/{{cookiecutter.repo_name}}/{{cookiecutter.repo_name}}/modules/__init__.py +++ /dev/null @@ -1 +0,0 @@ -'''Blueprint modules for {{cookiecutter.repo_name}}.''' diff --git a/{{cookiecutter.repo_name}}/{{cookiecutter.repo_name}}/modules/member.py b/{{cookiecutter.repo_name}}/{{cookiecutter.repo_name}}/modules/member.py deleted file mode 100644 index e732f6e..0000000 --- a/{{cookiecutter.repo_name}}/{{cookiecutter.repo_name}}/modules/member.py +++ /dev/null @@ -1,14 +0,0 @@ -# -*- coding: utf-8 -*- -'''Members-only module, typically including the app itself. -''' -from flask import Blueprint, render_template -from {{cookiecutter.repo_name}}.utils import login_required - -blueprint = Blueprint('member', __name__, - static_folder="../static", - template_folder="../templates") - -@blueprint.route("/members/") -@login_required -def members(): - return render_template("members.html") diff --git a/{{cookiecutter.repo_name}}/{{cookiecutter.repo_name}}/public/__init__.py b/{{cookiecutter.repo_name}}/{{cookiecutter.repo_name}}/public/__init__.py new file mode 100644 index 0000000..910bba4 --- /dev/null +++ b/{{cookiecutter.repo_name}}/{{cookiecutter.repo_name}}/public/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- +'''The public module, including the homepage and user auth.''' + +import views diff --git a/{{cookiecutter.repo_name}}/{{cookiecutter.repo_name}}/forms.py b/{{cookiecutter.repo_name}}/{{cookiecutter.repo_name}}/public/forms.py similarity index 66% rename from {{cookiecutter.repo_name}}/{{cookiecutter.repo_name}}/forms.py rename to {{cookiecutter.repo_name}}/{{cookiecutter.repo_name}}/public/forms.py index 2827a45..977ea53 100644 --- a/{{cookiecutter.repo_name}}/{{cookiecutter.repo_name}}/forms.py +++ b/{{cookiecutter.repo_name}}/{{cookiecutter.repo_name}}/public/forms.py @@ -1,17 +1,19 @@ -# -*- coding: utf-8 -*- from flask_wtf import Form from wtforms import TextField, PasswordField from wtforms.validators import DataRequired, Email, EqualTo, Length + class RegisterForm(Form): - username = TextField('Username', validators=[DataRequired(), Length(min=3, max=25)]) - email = TextField('Email', validators=[DataRequired(), Email(), Length(min=6, max=40)]) + username = TextField('Username', + validators=[DataRequired(), Length(min=3, max=25)]) + email = TextField('Email', + validators=[DataRequired(), Email(), Length(min=6, max=40)]) password = PasswordField('Password', validators=[DataRequired(), Length(min=6, max=40)]) - confirm = PasswordField( - 'Verify password', + confirm = PasswordField('Verify password', [DataRequired(), EqualTo('password', message='Passwords must match')]) + class LoginForm(Form): username = TextField('Username', validators=[DataRequired()]) password = PasswordField('Password', validators=[DataRequired()]) diff --git a/{{cookiecutter.repo_name}}/{{cookiecutter.repo_name}}/modules/public.py b/{{cookiecutter.repo_name}}/{{cookiecutter.repo_name}}/public/views.py similarity index 89% rename from {{cookiecutter.repo_name}}/{{cookiecutter.repo_name}}/modules/public.py rename to {{cookiecutter.repo_name}}/{{cookiecutter.repo_name}}/public/views.py index a38b4f6..e7909bd 100644 --- a/{{cookiecutter.repo_name}}/{{cookiecutter.repo_name}}/modules/public.py +++ b/{{cookiecutter.repo_name}}/{{cookiecutter.repo_name}}/public/views.py @@ -4,10 +4,10 @@ from flask import (Blueprint, request, render_template, flash, url_for, redirect, session) from sqlalchemy.exc import IntegrityError -from {{cookiecutter.repo_name}}.models import User -from {{cookiecutter.repo_name}}.forms import RegisterForm, LoginForm +from {{cookiecutter.repo_name}}.user.models import User +from {{cookiecutter.repo_name}}.public.forms import RegisterForm, LoginForm from {{cookiecutter.repo_name}}.utils import flash_errors -from {{cookiecutter.repo_name}}.models import db +from {{cookiecutter.repo_name}}.database import db blueprint = Blueprint('public', __name__, static_folder="../static", @@ -26,7 +26,7 @@ def home(): session['logged_in'] = True session['username'] = u.username flash("You are logged in.", 'success') - return redirect(url_for("member.members")) + return redirect(url_for("user.members")) return render_template("home.html", form=form) @blueprint.route('/logout/') diff --git a/{{cookiecutter.repo_name}}/{{cookiecutter.repo_name}}/templates/_layouts/nav.html b/{{cookiecutter.repo_name}}/{{cookiecutter.repo_name}}/templates/_layouts/nav.html index 7406f49..af4ef11 100644 --- a/{{cookiecutter.repo_name}}/{{cookiecutter.repo_name}}/templates/_layouts/nav.html +++ b/{{cookiecutter.repo_name}}/{{cookiecutter.repo_name}}/templates/_layouts/nav.html @@ -23,7 +23,7 @@ {% if session.logged_in %} Log out {% elif form %}