-
Notifications
You must be signed in to change notification settings - Fork 0
Large app how to
This document is an attempt to describe the first step of a large project structure with flask and some basic modules:
- SQLAlchemy
- WTF (What The Form)
Please feel free to fix and add you own tips.
[http://flask.pocoo.org/docs/installation/](Flask Installation) I recommend using virtual env: easy and allow multiple environment on the same machine and doesn't even require you to have super user right on the machine (as the libs are localy installed).
SQL provide an easy and advanced way to serialize your object to different type of relational database. In your virutal env, install SQLAlchemy from pip:
pip install flask-sqlalchemy
[http://packages.python.org/Flask-SQLAlchemy/](More here about SQL Alchemy flask package)
WTF (What the Form) Provides a easy way to handle user's data submission.
pip install Flask-WTF
[http://packages.python.org/Flask-WTF/](More here about What The Form flask package)
Ok, so from now, we should have all the libs ready. Here the folder structures:
config.py
run.py
shell.py
app.db
app/__init__.py
app/constants.py
app/static/
For every module (or sub app... ) well have this file structure (here for the users module)
app/users/__init__.py
app/users/views.py
app/users/forms.py
app/users/constants.py
app/users/models.py
app/users/decorators.py
for every module that need templating (jinja) we store those in the templates folder + module directory.
app/templates/404.html
app/templates/users/login.html
app/templates/users/register.html
...
for the static file you should serve them with a dedicated http server, but being in at a dev stage, we'll let flask serve them. Flask will automagically serve static files from this static folder. If you want to use another folder... you can read about that here: http://flask.pocoo.org/docs/api/#application-object
app/static/js/main.js
app/static/css/reset.css
app/static/img/header.png
We'll create 4 modules, a user module (manage user's registration, login, password lost, profile edit and maybe Third party Login/Registration) an emails module intended to be used by a queuing server, and a posts and comments modules
run.py will be used to launch the web server.
from tol import app
app.run(debug=True)
shell.py will allow you to get a console and enter commands within your flask environment. Maybe not as nice as debugging with pdb, but always usefull (when you will initialize your database)
#!/usr/bin/env python
import os
import readline
from pprint import pprint
from flask import *
from app import *
os.environ['PYTHONINSPECT'] = 'True'
config.py will be storing all the module configurations. Here, the database is setup to use SQLite, because it's a very convenient dev env database. Most likely config.py won't be a part of your repository and will be different on your test and production servers.
import os
_basedir = os.path.abspath(os.path.dirname(__file__))
DEBUG = False
ADMINS = frozenset(['youremail@yourdomain.com'])
SECRET_KEY = 'SecretKeyForSessionSigning'
SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(_basedir, 'app.db')
DATABASE_CONNECT_OPTIONS = {}
THREADS_PER_PAGE = 8
CSRF_ENABLED=True
CSRF_SESSION_KEY="somethingimpossibletoguess"
RECAPTCHA_USE_SSL = False
RECAPTCHA_PUBLIC_KEY = 'blahblahblahblahblahblahblahblahblah'
RECAPTCHA_PRIVATE_KEY = 'blahblahblahblahblahblahprivate'
RECAPTCHA_OPTIONS = {'theme': 'white'}
del os
-
_basediris a trick for you to get the folder where the script runs -
DEBUGindicate that it is a dev environment, you'll get the very helpful error page from flask when an error occur. -
SECRET_KEYwill be use to sign the cookies. Change it and all your user will have to login again. ADMINS-
SQLALCHEMY_DATABASE_URIandDATABASE_CONNECT_OPTIONSare SQLAlchemy connection options (hard to guess ) -
THREAD_PAGEmy understanding was 2/core... might be wrong :) -
CSRF_ENABLEDCSRF_SESSION_KEYis protecting against form post fraud - WTF comes with REPCAPTCHA field ready to use... just need to go to repcatcha website and get your public and private key.
We'll start with the users modules. In order, we'll define the models, the constants linked to this model, the form and finally the first view and it's template.
The models.py
from app import db
from app.users import constants as USER
class User(db.Model):
__tablename__ = 'users_user'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(50), unique=True)
email = db.Column(db.String(120), unique=True)
password = db.Column(db.String(20))
role = db.Column(db.SmallInteger, default=USER.USER)
status = db.Column(db.SmallInteger, default=USER.NEW)
def __init__(self, name=None, email=None, password=None):
self.name = name
self.email = email
self.password = password
def getStatus(self):
return USER.STATUS[self.status]
def getRole(self):
return USER.ROLE[self.role]
def __repr__(self):
return '<User %r>' % (self.name)
and it's constants in the constants.py file:
# User role
ADMIN = 0
STAFF = 1
USER = 2
ROLE = {
ADMIN: 'admin',
STAFF: 'staff',
USER: 'user',
}
# user status
INACTIVE = 0
NEW = 1
ACTIVE = 2
STATUS = {
INACTIVE: 'inactive',
NEW: 'new',
ACTIVE: 'active',
}
First about the constants file, I like to have my constants their own file and inside my module for 2 main reasons. Your constants will probably be used in your models, forms and views. The second reason is that it's a better organization for you to find them. Also, importing your constants as the module in uppercase indicate the constant type and the module name (like USER for users.constants) will avoid you name conflicts.
Now that we've done our object model, time to build the form that goes with it. We'll start with a registration form. The form will request the user's name, email and password. We'll use validators to ensure the user submitted correct values. Finally, a Repcaptcha field (provided by flask) will avoid machine registration. Just in case you plan on having Term of Service, I added a BooleanField called accept_tos. Since this field is required, the user will have to check the checkbox generated by this field on the box.
from flaskext.wtf import Form, TextField, PasswordField, BooleanField, RecaptchaField
from flaskext.wtf import Required, Email, EqualTo
class RegisterForm(Form):
name = TextField('NickName', [Required()])
email = TextField('Email address', [Required(), Email()])
password = PasswordField('Password', [
Required(),
EqualTo('confirm', message='Passwords must match')
])
confirm = PasswordField('Repeat Password')
accept_tos = BooleanField('I accept the TOS', [Required()])
repcaptcha = RecaptchaField()
The first parameters for the field is the label we'll want to display for the field. For example the name field will be labelled as NickName on the form.
Form more details of what can be done with WTF check [http://wtforms.simplecodes.com/docs/dev/]