Flask-Diamond Documentation
Flask-Diamond Documentation
Release 0.4.0
Ian Dennis Miller
May 22, 2016
Contents
1
Overview
1.1 Usage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.2 Documentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3
3
3
2
Introduction
2.1 Quick Start . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.2 Learn Flask-Diamond . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.3 System Requirements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5
5
6
6
3
Basics
3.1 Project Initialization and Scaffolding . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.2 Writing an Application with Flask-Diamond . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.3 Diagram of a Flask-Diamond Scaffold . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
9
9
11
14
4
Developer Guide
4.1 Model-View-Controller with Flask-Diamond . .
4.2 Models with SQLAlchemy . . . . . . . . . . . .
4.3 Views with Jinja and blueprints . . . . . . . . .
4.4 API with Flask-RESTful . . . . . . . . . . . . .
4.5 GUI with Flask-Admin . . . . . . . . . . . . . .
4.6 CRUD with Flask-Diamond . . . . . . . . . . .
4.7 Database Schema Migration with Flask-Migrate
4.8 Documentation with Sphinx . . . . . . . . . . .
4.9 Email with Flask-Mail . . . . . . . . . . . . . .
4.10 Testing with Nose . . . . . . . . . . . . . . . .
4.11 Users Accounts with Flask-Security . . . . . . .
4.12 Debugging a Flask-Diamond Application . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
17
17
18
22
25
27
30
31
34
36
36
38
38
User Guide
5.1 Requirements Management with virtualenv
5.2 Configuration Explanation . . . . . . . . . . . .
5.3 Makefile Explanation . . . . . . . . . . . . .
5.4 manage.py Explanation . . . . . . . . . . . .
5.5 Web Services with WSGI . . . . . . . . . . . .
5.6 IT Operations with Fabric . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
41
41
43
46
47
48
50
About Flask-Diamond
6.1 Libraries Included in Flask-Diamond . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6.2 Diagram of Libraries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
51
51
52
5
6
i
6.3
6.4
6.5
6.6
7
How to Contribute to the Project
Philosophy of Flask-Diamond .
Change Log . . . . . . . . . .
License . . . . . . . . . . . . .
.
.
.
.
54
54
55
61
API Reference
7.1 API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
63
63
Python Module Index
ii
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
71
Flask-Diamond Documentation, Release 0.4.0
Flask-Diamond is a batteries-included Flask framework. Easily scaffold a working application with sensible defaults,
then override the defaults to customize it for your goals.
Contents
1
Flask-Diamond Documentation, Release 0.4.0
2
Contents
CHAPTER 1
Overview
Flask-Diamond imports many other Flask extensions and glues them all together. The end result is a model administration view, accounts and high-level account operations (e.g. password reset), testing, documentation, deployment,
and more.
1.1 Usage
The following steps will create a new Flask-Diamond application.
mkdir my-application
cd my-application
mkvirtualenv -a . my-application
pip install Flask-Diamond
flask-diamond app .
make install docs test db server
You will need Python 2.7 or 3.4+, pip, virtualenv, and virtualenvwrapper. Please see the documentation for more
information.
1.2 Documentation
http://flask-diamond.readthedocs.org
3
Flask-Diamond Documentation, Release 0.4.0
4
Chapter 1. Overview
CHAPTER 2
Introduction
2.1 Quick Start
Flask-Diamond installs in a Python environment with virtualenv. Please see the System Requirements for information
about installation pre-requisites.
2.1.1 Install Flask-Diamond
Create a virtualenv for your new Flask-Diamond application, and then install Flask-Diamond with pip.
mkdir my-application
cd my-application
mkvirtualenv -a . my-application
pip install Flask-Diamond
2.1.2 Scaffold a new Flask-Diamond application
Create a directory to hold your application, and then scaffold a new Flask-Diamond application inside that directory.
For this Quick Start, just use the default options.
workon my-application
flask-diamond app .
make install test
2.1.3 Use it!
Create the database:
make db
Start the server:
make server
You now have a server running at http://127.0.0.1:5000/admin. Visit your new application in a web browser and login
with the following account details:
• username: admin
• password: aaa
5
Flask-Diamond Documentation, Release 0.4.0
2.1.4 Next Steps
It’s easy to scaffold a Flask-Diamond application. Now you can Learn Flask-Diamond by reading the online materials.
2.2 Learn Flask-Diamond
The best way to learn Flask-Diamond is to read the Developer Guide; contained within is a growing list of documents
that explain various aspects of the Flask-Diamond approach. To help new learners focus on the fundamentals, read the
following documents first.
• Quick Start shows you how to scaffold a new application. You can be up and running in just a few minutes.
• Project Initialization and Scaffolding offers many options for you to customize your application. Read this
document to learn more about answering the questions during scaffolding.
• Model-View-Controller with Flask-Diamond describes the architecture provided by Flask-Diamond. ModelView-Controller (MVC) is widely used in software engineering to write applications that provide a user interface. Once you understand how to implement MVC using Flask-Diamond, you will be able to write applications
for a wide range of domains.
• Writing an Application with Flask-Diamond provides examples and describes an approach for designing and
programming something that achieves your goals.
2.2.1 Learning Python
If you are relatively new to Python, you may find that there are advanced computer science principles that FlaskDiamond requires some knowledge of. In particular, Flask-Diamond applications are heavily Object Oriented and
make extensive use of Inheritance.
There are many tutorials online that can help you to learn about these fundamentals. In particular, I recommend the
following:
• Dive Into Python
• Learn Python the Hard Way
2.3 System Requirements
Flask-Diamond requires some software to be installed in order to function. Once you have installed these requirements,
you can follow the Quick Start to start your first project. The following packages should be installed globally, as the
superuser, for all users on the system to access.
• Python 2.7.x or 3.4 and above.
• Python development libraries (i.e. header files for compiling C code)
• pip
• virtualenv
• virtualenvwrapper
The following sections describe the process for installing these requirements on various systems. In each of the
following examples, it is assumed you will be using a root account (or some other privileged account).
If you do not have root access, then refer to the section Unprivileged Installation for information about creating a
virtualenv in your user account.
6
Chapter 2. Introduction
Flask-Diamond Documentation, Release 0.4.0
2.3.1 Debian/Ubuntu
Flask-Diamond installs cleanly on Debian and Ubuntu systems released after 2011.
apt-get install python python-dev python-pip build-essential
apt-get install sqlite-dev
pip install --upgrade pip
pip install --upgrade virtualenv
pip install virtualenvwrapper
2.3.2 Redhat
Flask-Diamond can be installed on RedHat, but ensure your package manager is installing Python 2.7; as of August
2015, RHEL provides an older version.
yum
yum
pip
pip
pip
install
install
install
install
install
python python-devel python-pip
sqlite-devel
--upgrade pip
--upgrade virtualenv
virtualenvwrapper
2.3.3 OSX with Homebrew
Flask-Diamond installs pretty easily on OSX with Homebrew. Make sure you are using the admin user for this process,
just like a normal Homebrew operation.
brew install python --universal --framework
brew install pyenv-virtualenv
brew install pyenv-virtualenvwrapper
brew install sqlite
pip install --upgrade pip
2.3.4 Windows with Cygwin
Note: Have you done this install successfully? Please share your process as a comment on Issue 8.
Here are a few resources to get you started:
• http://www.pdxpixel.com/blog/setting-up-python-and-virtualenv-windows-cygwin/
• http://atbrox.com/2009/09/21/how-to-get-pipvirtualenvfabric-working-on-cygwin/
• http://anythingsimple.blogspot.ca/2010/04/using-pip-virtualenv-and.html
• http://stackoverflow.com/questions/2173963/how-do-i-get-virtualenvwrapper-and-cygwin-to-co-operate
2.3.5 Unprivileged Installation
Sometimes, you do not have root access to the system. It is still possible to use Flask-Diamond, but the installation
process is slightly different because it does not use virtualenvwrapper. Instead, you will create your virtualenv directly
and use the activate macro to work on it.
2.3. System Requirements
7
Flask-Diamond Documentation, Release 0.4.0
curl -O https://raw.github.com/pypa/virtualenv/master/virtualenv.py
python virtualenv.py my-diamond-app
. my-diamond-app/bin/activate
pip install Flask-Diamond
8
Chapter 2. Introduction
CHAPTER 3
Basics
The basics: how to start a new project and the first steps for making a Flask-Diamond application.
3.1 Project Initialization and Scaffolding
The quickest way to start a new Flask-Diamond project is to use the scaffolding system. Scaffolding applies a series
of file templates that result in a starter application that can be further customized. This document discusses the
configuration questions that are used during scaffolding.
As described in the Quick Start, the basic process looks like this:
mkdir my-application
cd my-application
mkvirtualenv -a . my-application
pip install Flask-Diamond
flask-diamond app .
make install docs test db server
3.1.1 About Scaffolding
When you invoke flask-diamond, a template is automatically applied. Using mr.bob, a brief set of questions are
used to populate the templates with variables. When you answer these questions, your choices are stored in a file
called .mrbob.ini that is located in the root folder of your project.
3.1.2 Template questions
This template is suitable for supporting many types of Python projects. It will create a basic directory structure that
provide requirements management, documentation, build, deployment, and other basic project needs. This step of the
scaffolding process asks the following questions:
1. What is the name of the application (i.e. username, daemon name, etc)?
Example: Flask-Diamond
The application name is a human-readable name that will be used in documentation, on websites, and when talking
about the project. This should follow conventions that are established within your community. In the case of FlaskDiamond, the project name tries to follow the naming pattern established by other Flask extensions like Flask-Admin,
Flask-Security, and Flask-RESTful.
9
Flask-Diamond Documentation, Release 0.4.0
2. What is the name of the module (can be different from the application name)?
Example: flask_diamond
The module name is a PEP8 styled name. In the case of Flask-Diamond, the module name should be lowercase and
hyphens become underscores. Thus, Flask-Diamond becomes flask_diamond.
3. What is the short description for this project?
Example: Flask-Diamond is a batteries-included Flask framework.
This question corresponds to the setuptools.setup(description="") variable in the project setup.py file.
The short description is intended to appear as a brief summary in PyPI.
4. What is the long description for this project?
Example: Flask-Diamond is a batteries-included Flask framework. Easily scaffold
a working application with sensible defaults, then override the defaults to
customize it for your goals.
This question corresponds to the setuptools.setup(long_description="") variable in the project
setup.py file. In practice, this usually ends up being multiple paragraphs.
5. Who is the author of this software?
Example: Ian Dennis Miller
This question corresponds to the setuptools.setup(author="") variable in the project setup.py file. It’s a
name. Your name.
6. What is the author’s contact email?
Example: [email protected]
This question corresponds to the setuptools.setup(author_email="") variable in the project setup.py file.
This is your public contact information.
7. What is the author’s contact URL?
Example: http://flask-diamond.org
This question corresponds to the setuptools.setup(url="") variable in the project setup.py file. If you have
a website that provides support for your project, put it here. In the case of Flask-Diamond, there are lots of resources
on the official website, including a link to the project issue tracker. As a result, Flask-Diamond uses the project URL
as the contact URL.
8. What ssh key is used to deploy?
Example: ~/.ssh/id_rsa
This question corresponds to fabric.api.env.key_filename inside fabfile.py, which is the SSH key
filename that is used to deploy the project to a remote host via SSH.
10
Chapter 3. Basics
Flask-Diamond Documentation, Release 0.4.0
9. Where is the git repository?
Example: https://github.com/iandennismiller/flask-diamond
If you will be distributing your application through hosted version control, then provide the URL here. This is used
during deployment, and it is useful for reference.
10. Which port will the daemon listen on?
Example: 5000
Your application will run as an HTTP service that listens on the port provided here. Thus, if you answer 8000 you
will be able to connect to your application at http://localhost:8000/admin.
3.1.3 Automatically generated scaffolding fields
There are some steps in the scaffolding process that are automatically generated for you because they involve random
processes.
1. What is the secret key?
Example: \x83.RH\[email protected]\x0fu\xb5o\xcd\xf5\xc4\xd5\xb12\xc2M\xca\x96\xc8\xbf\xeb\xde
Flask uses a secret key to seed certain cryptographic functions. To generate a suitable random string for the secret key,
use the following Python code:
python -c 'import os; print(repr(os.urandom(24)))'
2. What is the hash_salt?
Example: t52ybrp0oOGHkQEZ
Flask uses a hash salt for password storage. To generate a suitable random string for the hash salt, use the following
Python code:
python -c 'import string as s, random as r; \
print repr("".join(r.choice(s.letters+s.digits) for _ in range(16)))'
3.2 Writing an Application with Flask-Diamond
By default, Flask-Diamond is ready to run when you initially scaffold a new application. This document describes the
customization process, which transforms the default application into something tailored to your goals. We will start
by discussing the default start-up routine for all Flask-Diamond applications, and then talk about modifying start-up
to change its behavior.
3.2.1 A basic Flask-Diamond Example
The following example can be generated from a freshly scaffolded project by following the Project Initialization and
Scaffolding document with the project name MyDiamondApp. Notice that the MyDiamondApp class inherits from
Diamond, which gives the new project a lot of functionality “out of the box.”
3.2. Writing an Application with Flask-Diamond
11
Flask-Diamond Documentation, Release 0.4.0
from flask.ext.diamond import Diamond, db
from flask.ext.diamond.facets.administration import AdminView, AdminModelView
app_instance = None
from . import models
class MyDiamondApp(Diamond):
def init_blueprints(self):
self.super("blueprints")
from .views.administration.modelviews import adminbaseview
self.app.register_blueprint(adminbaseview)
def create_app():
global application
if not application:
application = Diamond()
application.facet("configuration")
application.facet("logs")
application.facet("database")
application.facet("marshalling")
application.facet("accounts")
application.facet("blueprints")
application.facet("signals")
application.facet("forms")
application.facet("error_handlers")
application.facet("request_handlers")
application.facet("administration")
# application.facet("rest")
# application.facet("webassets")
# application.facet("email")
# application.facet("debugger")
# application.facet("task_queue")
return application.app
Customization with Inheritance
In the basic example above, notice the function blueprints(). This function handles the initialization of Flask
blueprints. By overloading 1 this functions (and others) within your application, it is possible to customize the start-up
behavior of any subsystem. Every subsystem in the Flask-Diamond start-up can be configured. For a complete list of
the functions you can overload, refer to the extensions argument in the Diamond object documentation.
Enable or Disable Functionality
Flask-Diamond functionality is initialized using extensions. In case you wish to disable certain functionality, you
may simply omit that initialization step from the extensions list. For example, to enable REST functionality, omit
email initialization from the extensions passed to create_app(). Many extensions can be enabled/disabled with ease,
including rest, webassets, email, debugger, and task_queue.
Other extensions, like blueprints, are fundamental to the behavior of a Flask application, and are therefore trickier to
disable in Flask-Diamond. In those cases, it may be better to override the initialization function using inheritance.
Inheritance also permits functionality to be disabled. For example, to completely disable email, it is possible to
overload the email startup with a function that does nothing. It looks like this:
1
“Overloading” is the process of creating a function with the same name as a function in the class you’re inheriting from. In the example above,
we have overloaded administration() and blueprints().
12
Chapter 3. Basics
Flask-Diamond Documentation, Release 0.4.0
def init_email(self):
pass # do nothing
3.2.2 Application start-up
Flask-Diamond initializes many subsystems when the application is first started. The subsystems are initialized in this
order:
1. flask_diamond.facets.configuration. the $SETTINGS environment variable is inspected and the
file it points to is loaded.
2. flask_diamond.facets.logs. based on the configuration, write log messages to a file on the filesystem.
3. flask_diamond.facets.database. connect to a database and initialize the SQLAlchemy Object Relational Mapper (ORM)
4. flask_diamond.facets.accounts. manage users, roles, login, passwords, and other security things
with Flask-Security.
5. flask_diamond.facets.blueprints. initialize your application’s views (in the MVC sense), which
are saved as “blueprints” in a Flask application.
6. flask_diamond.facets.signals. Flask provides a signals subsystem that your application can hook
into to automate certain behaviors.
7. flask_diamond.facets.forms. initialize your application’s form helpers, which may be global to the
forms used in your application.
8. flask_diamond.facets.handlers. when something goes wrong, you may want to handle it (e.g. by
displaying a 404 page)
9. flask_diamond.facets.handlers. This is the place to create redirections or other custom request
handlers that extend beyond views.
10. flask_diamond.facets.administration. a quick GUI using Flask-Admin with extensive Model
support.
11. flask_diamond.facets.rest. provide a REST API using Flask-RESTful
12. flask_diamond.facets.webassets. it is possible to bundle assets like images, CSS, and javascript
with your application. webassets simplifies some of this work.
13. flask_diamond.facets.email. send email with Flask-Mail
14. flask_diamond.facets.debugger. when the configuration specifies that DEBUG = True, the web
interface will display a widget with extra debugging tools.
15. flask_diamond.facets.task_queue. provide a task queue using Celery
3.2.3 Extending the Scaffold
The scaffold files are a starting point, and you will probably end up creating many new files in the course of writing
your application. You can think about the scaffold as being sortof similar to inheritance; if you want to change one
of the default files, just overwrite it with your own. By customizing the scaffold, you can easily create new models,
views, security views, administration views, API endpoints, and more.
Additional scaffolds are distributed along with Flask-Diamond. They are stored in $VIRTUAL_ENV/share/skels
and can be applied manually using mr.bob. Additional scaffolds describe common patterns for using Views and
Models.
3.2. Writing an Application with Flask-Diamond
13
Flask-Diamond Documentation, Release 0.4.0
It is recommended to stick with the directory structure in the beginning. As with anything, you are free to change the
structure, but if you learn how to work within it, your applications will be easier to maintain and deploy - especially
when you have dozens of Flask-Diamond applications to manage!
3.2.4 Further Reading
Several guides have been created to discuss Flask-Diamond application building in greater detail:
• Models with SQLAlchemy
• GUI with Flask-Admin
• Views with Jinja and blueprints
3.3 Diagram of a Flask-Diamond Scaffold
When a new Flask-Diamond project is scaffolded, it will generate files in roughly the following layout. The SVG
scaffold diagram is also available for download.
14
Chapter 3. Basics
Flask-Diamond Documentation, Release 0.4.0
3.3. Diagram of a Flask-Diamond Scaffold
15
Flask-Diamond Documentation, Release 0.4.0
16
Chapter 3. Basics
CHAPTER 4
Developer Guide
Once you have a project to work with, more advanced topics are discussed in the Developer Guide. These topics are
for developers who are writing or maintaining Flask-Diamond applications.
4.1 Model-View-Controller with Flask-Diamond
Model-View-Controller (MVC) is a popular architecture for designing applications that have a user interface. At its
heart, MVC is a collection of software design patterns that provide a vocabulary for designing your application. When
you “speak MVC,” other people who also know MVC will understand what you are saying.
The MVC vocabulary consists of:
• Models: a way for talking about data
• Views: a way for talking about user interfaces
• Controllers: a way for talking about program logic
This document presents an overview of Model-View-Controller and links to more detailed documentation that discusses these ideas in greater detail.
4.1.1 Model
A model is usually named after a noun. A model is a data representation of something that exists, and just about
anything that exists can be modeled.
Entities and Relationships
To model a chess game, you’d start with a model of Players and Chess Pieces, which are entities. A player has many
chess pieces, so there is a relationship between our entities. Using nothing more than the idea of “Players” and “Chess
Pieces”, you can go a long way towards modeling the game of chess.
All models have two properties:
• Entities: An Entity is a type of object. Entities have attributes, which are characteristics of the Entity. In the
chess example, a Player is a an Entity; there are two Players in chess and each one is an instance of the Player
class. An attribute of Players is “color”; the player controls either white pieces or black pieces, so the player’s
color can be white or black. Since a player can have a name, name is therefore also an attribute of a Player.
17
Flask-Diamond Documentation, Release 0.4.0
• Relationships: Entities can affect one another through relationships. In the chess example, a Player has many
Pieces and each Piece is owned by a Player. Since a Player can have many Pieces, we call this a “one-to-many”
Relationship. There are also one-to-one and many-to-many relationships.
A model can therefore be described using an Entity-Relationship Diagram, which shows all of the types of objects,
their attributes, and the way entities relate to one another. Read more about Models with SQLAlchemy for a more
detailed discussion and code examples.
A Philosophy of Models
A model might be a very simple representation of a real thing, or the model might be very detailed. A model of an
entire country’s economy might require lots of detail, whereas a model of a school district might be relatively simpler.
A model is in some ways a platonic ideal of the actual domain being modeled. While things in the “real world” are
irregular in an uncountable number of ways, our models are perfectly regular. Since models are stored in a database,
all of the model attributes can be lined up nicely into rows and columns. Tidy!
Paradoxically, a model is always an imperfect representation of the thing it is modeling. The irregularities of the real
world are difficult to capture using a model. The goal for good model creation is to isolate the parts of the model that
are regular so as to reduce the number of exceptions to your model.
Sometimes, we talk about “domains” when we talk about models, because our models might be thematically related
to one another. A domain might be something like finance, gaming, email, or any other broad category that people
build applications for. To properly model a domain, we might talk to a “domain expert” to learn more about the kinds
of models we are building.
4.1.2 View
A view is a user interface that can present data that comes from a model. In classic MVC, the model pushes data to the
view, and the view knows how to update itself to display the data that was received from the model. Views can also
contain input elements like buttons, fields, and sliders. When these input elements are activated, the Controller must
decide how to respond. Views are often written as templates that have placeholders for data. For web programming,
a View template is frequently written using HTML 1 . Read more about Views with Jinja and blueprints for a more
detailed discussion and code examples.
4.1.3 Controller
A controller responds to input by changing a view or model. A common type of controller is driven with a Graphical
User Interface, which uses things like menus, fields, and buttons so that a human can click stuff to get things done.
Read more about GUI with Flask-Admin for a more detailed discussion.
A different type of controller is an API, which is typically used by other software (rather than a human) to make the
application do something. Read more about API with Flask-RESTful for a more detailed discussion.
4.2 Models with SQLAlchemy
In Flask-Diamond, a Model is a way of reading and writing a database. If our application is a chess game, then we’re
modeling chess objects in a database. If our application is a social network, then we’re modeling people objects in
a database. A fundamental assumption of the Model-View-Controller architecture is that our application deals with
objects, and our objects are modeled after the things our application deals with.
1 There’s nothing inherently special about HTML templates for constructing Views. For example, Android Views can be constructed using Java.
The point is that the idea of views can be generalized to any platform.
18
Chapter 4. Developer Guide
Flask-Diamond Documentation, Release 0.4.0
This document will demonstrate a model, then discuss some of the ways Flask-Diamond makes it easier to work with
models.
4.2.1 A Basic Model
A model is actually written in Flask-Diamond using Python. Models are represented using SQLAlchemy, which is a
very powerful Python library for working with databases. Since we are storing our models in a database, SQLAlchemy
provides a strong foundation for getting the job done.
Let’s create a model of a person who has a name and an age. Also, let’s model the fact that every person has two
biological parents (here called a mother and a father). The following example demonstrates one way this model might
be accomplished. 2
from flask.ext.diamond.utils.mixins import CRUDMixin
from flask.ext.diamond import db
class Person(db.Model, CRUDMixin):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(255))
age = db.Column(db.Integer)
mother_id = db.Column(db.Integer, db.ForeignKey('person.id'))
mother = db.relationship('Person',
primaryjoin=('Person.mother_id == Person.id'),
remote_side="Person.id")
father_id = db.Column(db.Integer, db.ForeignKey('person.id'))
father = db.relationship('Person',
primaryjoin=('Person.father_id == Person.id'),
remote_side="Person.id")
def __str__(self):
return self.name
Now, we can model a Person and specify their name and age. Once we create Person objects for a mother and a father,
we can model the parent-child relationships. The model above could be used in Python like so:
from models import Person
me = Person.create(name="Me", age=34)
mom = Person.create(name="Mom", age=65)
dad = Person.create(name="Dad", age=64)
me.mother = mom
me.father = dad
me.save()
4.2.2 Model Methods
Usually, data models are created for entities that are changing. A person’s age increases every year, so we might create
a birthday method that increments a person’s age. A simplified version of our person model has been extended with
the birthday method below:
2 Note the use of CRUDMixin, which provides us with a create() method. For more information about CRUDMixin, see CRUD with FlaskDiamond.
4.2. Models with SQLAlchemy
19
Flask-Diamond Documentation, Release 0.4.0
class Person(db.Model, CRUDMixin):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(255))
age = db.Column(db.Integer)
def birthday(self):
self.age += 1
self.save()
Only The Model Controls the Data
It is important to contain any data-altering methods within your Model, or else there may be confusion down the road.
For example, if there is code within the Controller that directly alters the data Model, you should move that code from
the Controller to a new Model method that achieves the same task. Finally, in the controller, invoke the Model method.
4.2.3 SQLAlchemy
SQLAlchemy and Flask-SQLAlchemy are used to provide an Object Relation Mapper (ORM), which reads/writes a
database and makes the data easy to access using Python. By using an ORM such as SQLAlchemy, it is possible to
avoid many pitfalls of directly using SQL, such as SQL injections or schema mismatches. One of the best resources
to learn about writing models is the SQLAlchemy documentation itself, which is both excellent and extensive.
Model Relationships with SQLAlchemy
The SQLAlchemy Basic Relationships document provides an excellent overview of different relationship patterns,
including:
• One to Many
• Many to One
• One to One
• Many to Many
• Many to Many Association
To demonstrate a basic relationship, let’s say each Person lives in a House, which is modeled as:
class House(db.Model, CRUDMixin):
id = db.Column(db.Integer, primary_key=True)
address = db.Column(db.String(255))
class Person(db.Model, CRUDMixin):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(64))
house_id = db.Column(db.Integer, db.ForeignKey("house.id"))
house = db.relationship('House',
backref=db.backref('persons', lazy='dynamic')
)
The following code example uses the classes above to create two people who live at one house.
our_house = House(address="1600 Pennsylvania Ave")
myself = Person("Me", house=our_house)
mom = Person("Mom", house=our_house)
print(myself.house)
20
Chapter 4. Developer Guide
Flask-Diamond Documentation, Release 0.4.0
Querying with SQLAlchemy
Based on the Person class, a simple query that finds a person named “Me” looks like:
myself = models.Person.find(name="Me")
print(myself.name)
However, the SQLAlchemy Query API is extremely powerful, and its documentation is the authoritative source.
4.2.4 When the Model Changes
There is a close correspondence between the Model and the database tables. If an attribute is added to a model, then
we need a new column in our database to store the values for this attribute. If the model changes, the database must
also change. There are two ways of updating your database:
• the clean slate: delete the old database and creating a new one that reflects the latest changes to the model. This
is accomplished with make db on the command line. It’s easy and quick.
• schema migrations: analyze your updated model to determine what parts are different from your old database,
and then add/remove those parts to a live database. This is tricky, but it is necessary for databases in production.
Read more in Database Schema Migration with Flask-Migrate.
As long as you are actively developing, it is recommended to use make db each time you update your model.
However, when your application is live, you will need to read Database Schema Migration with Flask-Migrate to
learn about altering a production database.
4.2.5 Data Fixtures
What good is a data model without any data to put in it? Data fixtures are a way of easily adding data to your database,
which is helpful when you are frequently rebuilding your database with make db. Data fixtures can be placed into
bin/manage.py within the populate_db() function. If you find yourself continually re-creating certain model
objects in your database so you can test your application, then consider using populate_db() to automate the
creation of these objects.
For example, in order for make db to automatically create a Person object based on the Person class above, construct
populate_db() like this:
@manager.command
def populate_db():
"insert a default set of objects"
from models import Person
me = Person.create(name="Me", age=34)
mom = Person.create(name="Mom", age=65)
dad = Person.create(name="Dad", age=64)
me.mother = mom
me.father = dad
me.save()
4.2.6 Another model example
class Individual(db.Model, CRUDMixin):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(255))
4.2. Models with SQLAlchemy
21
Flask-Diamond Documentation, Release 0.4.0
friend_id = db.Column(db.Integer, db.ForeignKey('individual.id'))
friend = db.relationship('Individual',
primaryjoin=('Individual.friend_id == Individual.id'),
remote_side="Individual.id")
def set_friend(self, obj):
self.friend = obj
self.save()
def as_hash(self):
pass
def __str__(self):
return self.name
4.2.7 Further Reading
• See Database Schema Migration with Flask-Migrate, which describes how to evolve the application database
along with its Model.
• See CRUD with Flask-Diamond, which describes the Create-Read-Update-Delete pattern for Models.
• See GUI with Flask-Admin, which explains how to create a GUI for interacting with Models.
4.3 Views with Jinja and blueprints
As is explained in Model-View-Controller with Flask-Diamond, a View takes data from a Model and presents it (typically to a user). Often times, there are multiple Views of a data Model, and they may present different aspects of
the Model. A common pattern for multiple views is the use of permissions to restrict functionality to users based
upon their account role. The administrator may have a special View into the data that provides extra functionality that
regular users do not have.
Views are frequently written using templates, which have placeholders for variables that may be filled in by the
application. In Flask-Diamond, the Jinja templating language is used to generate HTML, javascript, CSS, and other
web-facing files that create a user interface. By populating the template with data from the Model, the result is that
users can interact with Model data.
4.3.1 Jinja is a Templating Language
The rest of this document provides a summary of the key points about Jinja Views. The Jinja website provides a nice
example of what Jinja looks like:
{% extends "layout.html" %}
{% block body %}
<ul>
{% for user in users %}
<li><a href="{{ user.url }}">{{ user.username }}</a></li>
{% endfor %}
</ul>
{% endblock %}
A detailed discussion of templates is available from the Jinja templates documentation.
22
Chapter 4. Developer Guide
Flask-Diamond Documentation, Release 0.4.0
Variables in Jinja
A python expression within a Jinja template is denoted using double-curlies as {{ }}. In this manner, it is easy
to reference variables by simply placing them inside double-curlies. In the example above, user.username will be
replaced by the actual value of a user’s username (e.g. “administrator”). If it were not inside the double-curlies,
“user.username” would be printed verbatim (i.e. substitution is not performed unless inside double-curlies).
Statements in Jinja
A python statement (like an “if statement”) is denoted in Jinja using {% %}. Using statements, it is possible to create
dynamic templates that print different details based upon the data given to them. For example, in a chess game, each
player would view the chess board from opposite sides of a table, so the view should display the board differently to
each player. A logic statement like {% if player.color==’white’ %} can be used to display the board in
one direction to the white player, and {% if player.color==’black’ %} can do the opposite.
4.3.2 Rendering a template with Flask
Flask provides an easy mechanism for working with templates that is called render_template(). When a template is
rendered with data, the placeholders inside the template are replaced with the data. In the case of web applications,
the result is typically an HTML document that presents the application’s data model in a format that a human could
use through a web browser.
To render the previous template, first save it to a file called “my_template.html” and place that in a directory called
“templates”.
The code looks like:
my_data = {"users": [{"username": "administrator", "url", "http://utoronto.ca"}]}
return flask.render_template("my_template.html", **my_data)
Flask searches for templates by looking through a directory called “templates”. This behaviour can be extended by
using Blueprints, which are explained a little later in this document. More information about Flask and templates is
available from the Flask templating documentation.
4.3.3 Routing a View
URLs are used within web applications to identify Views. In the case of a chess game application, the URL /piece_list
could return with a summary of all the chess pieces, and /piece/black/pawn/1 could provide information about the
black player’s first pawn.
When building an MVC View for a web application, the Controller is responsible for actually routing the user to the
View. MVC Web applications use the URL to connect with a view, such that a user can use their web browser to
request /user/login_form in order to log in to a website or view the /player/white/pieces to figure out the score in a
game of chess. In Flask, the route() decorator is used to apply a route to a View function.
A simple route looks like:
@app.route('/')
def index():
return "Hello world!"
The Site Map is used to determine all the routes that will be necessary for exposing a web application. Every View
must be present within the Site Map, and there must be a unique URL for each View.
It is possible to look at a Flask-Diamond web application site map from within the application itself:
4.3. Views with Jinja and blueprints
23
Flask-Diamond Documentation, Release 0.4.0
print flask.current_app.url_map
4.3.4 Flask Blueprints: a Collection of Views
Often times, there will be several related views and it makes sense to collect these together using a Flask Blueprint.
When this happens, the views are collected into a URL subdirectory, and individual views are nested within that URL.
For example, in a game of chess, there may be several views related to players and several related to pieces, which
could be collected into the /player directory and the /piece directory.
The Flask documentation demonstrates an extremely simple blueprint:
from flask import Blueprint, render_template, abort
from jinja2 import TemplateNotFound
simple_page = Blueprint('simple_page', __name__,
template_folder='templates')
@simple_page.route('/', defaults={'page': 'index'})
@simple_page.route('/<page>')
def show(page):
try:
return render_template('pages/%s.html' % page)
except TemplateNotFound:
abort(404)
This example demonstrates everything we have discussed so far:
• the render_template function
• the template_folder that contains Jinja templates
• routing the View to a URL with route()
The Flask documentation also explains how to register a blueprint with an application:
from flask import Flask
from yourapplication.simple_page import simple_page
app = Flask(__name__)
app.register_blueprint(simple_page)
4.3.5 Views within Flask-Admin BaseModelView
In Flask-Admin, each BaseModelView is actually a Blueprint that provides views for creating, reading, updating, and
deleting model objects. The BaseModelView template behaves much like a regular blueprint, except:
• expose() is used to “expose” a view inside BaseModelView instead of route()
• self.render() is used instead of render_template
In this manner, it becomes easy to extend a CRUD with custom methods that go beyond create, read, update, and
delete.
24
Chapter 4. Developer Guide
Flask-Diamond Documentation, Release 0.4.0
4.3.6 Another admin view
{% extends 'admin/model/edit.html' %}
{% block body %}
{% block model_menu_bar %}
<ul class="nav nav-tabs">
<li>
<a href="{{ url_for('.index_view') }}"><i class="icon-list-alt"></i> {{ _gettext('List')
</li>
<li class="active">
<a href="{{ url_for('.index_view') }}"><i class="icon-eye-open"></i> Individual</a>
</li>
</ul>
{% endblock %}
{% block model_content %}
<h2>Individual</h2>
<ul>
<li>ID: <b>{{ model.id }}</b></li>
</ul>
{% endblock %}
{% endblock %}
4.4 API with Flask-RESTful
One of the most common ways to build an API is using a paradigm called REST. Flask-RESTful is a great library
for Flask that simplifies the creation of a REST API. This document describes REST and how to implement it in a
Flask-Diamond project.
4.4.1 REST in a Nutshell
I like to simplify REST like so:
• The web consists of documents that are referred to by URL links.
• Each URL is a “thing”. As a part of speech, it is a noun. For example: a URL points to a picture, a document,
or a person’s timeline.
• The language spoken by web browsers and web servers is called HTTP. This is the protocol for “hypertext”.
• HTTP provides actions (verbs) like GET, PUT, DELETE, and POST.
• Using HTTP and URLs provides verbs and nouns that we can use to write statements, like “GET a Picture” or
“DELETE a Document”.
REST is a strong statement about the grammar of the web. It tells us where the nouns are and where the verbs are.
If we learn to make APIs that are RESTful, then we can count on others to be able to use our APIs in natural ways to
create complex expressions.
4.4. API with Flask-RESTful
25
Flask-Diamond Documentation, Release 0.4.0
Examples of REST
Let’s say you are building an API for chess. The main thing players must do is change the lay of the board by moving
pieces. Our API therefore exposes one endpoint: /api/board. To change the board, we will update it by providing
a standard chess move that takes a piece from one location and moves it to another. We will use JSON to represent the
move like so:
{
'from': 'A2',
'to': 'C3'
}
So, to put a knight into a new spot, we might issue the following HTTP command:
PUT /api/board HTTP/1.1
{'from': 'A2', 'to': 'C3'}
Such a command could be issued using javascript, from the command line (e.g. with curl), or using any HTTP client.
That’s the beauty of REST: if you work with the web, the web can work with you.
4.4.2 Flask-RESTful
It is easy to create RESTful APIs with Flask-RESTful, which is already integrated into Flask-Diamond.
The primary way to use Flask-RESTful is to create Resource objects. A Resource is a “thing” that your API will
expose. You can easily add API Resources to your Flask-Diamond application by placing them into a function called
init_rest():
def init_rest():
class Board(Resource):
def get(self, id):
return models.board.get(id).dumps()
def put(self, id):
board = models.board.get(id)
board.move_piece()
rest.add_resource(Board, '/api/board/<int:id>')
This simple example creates a resource called Board. Then, it specifies a way to handle the GET verb, which will
result in retrieving a board. It also specifies how to handle the PUT verb, which it will respond to by moving a piece.
Finally, the resource is exposed using a URL: /api/board/....
If you were to place this code into your own application alongside your init_blueprints() function, you will suddenly
have an API for your app!
4.4.3 MarshmallowMixin
flask_diamond.mixins.marshmallow.MarshmallowMixin simplifies object marshalling, which is the
process of mapping data to and from a serialization format like JSON. This functionality is provided by Marshmallow
and Flask-Marshmallow.
Marshalling is useful because applications must frequently send model data across the Internet, and in order to do so,
models are commonly translated into JSON or another format. For example, date and time objects are native Python
objects that must be converted to a string in order for JSON to transmit them. Marshalling makes serialization and
deserialization into a repeatable process.
26
Chapter 4. Developer Guide
Flask-Diamond Documentation, Release 0.4.0
Let’s look at the following line of code:
return models.board.get(id).dumps()
The dumps() at the end of the line will cause an ORM model object to be converted to JSON using Marshmallow. For
more information, please see the documentation for Marshmallow and Flask-Marshmallow.
4.4.4 How not to REST
REST says we should not create URLs that imply actions; URLs must be things. This pattern is common in older
websites. For example, you should not build an API with a URL called /api/move_piece because that describes
an action: moving a piece. REST says the only actions available are HTTP verbs, like GET and PUT.
You can think about it this way too: when a web client visits a URL, it usually issues the GET verb. It doesn’t really
make sense to GET /api/move_piece. However, early web developers tried to make this work using arguments.
That resulted in operations like GET /api/move_piece?from=A2&to=C3. These became really long URLs
that contained all the same information as the RESTful example, but which broke certain features of the Internet. For
example, if a web spider visited that URL, the web server would incorrectly interpret that visit as a command to move
a piece.
This leads to chaos. Don’t make URLs this way. Be RESTful, instead.
4.5 GUI with Flask-Admin
A common pattern in application design is to apply CRUD to your Model, and then provide a Graphical User Interface
for people to interact with the Model. Flask-Admin makes it very easy to create a basic interface with Create-ReadUpdate-Delete functionality, and provides a framework for designing much more sophisticated interfaces.
This document discusses a simple CRUD with Flask-Admin, and then extends the CRUD with additional functionality.
4.5.1 A Simple CRUD GUI
When Flask-Admin creates a GUI, it automatically discovers the Model Attributes and creates a web form containing
fields for all the attributes. Flask-Admin provides the BaseModelView class as the foundation for building Views that
a user can interact with to inspect and control a Model. Flask-Diamond provides AdminModelView, which applies an
authentication requirement so that only users with the Admin role can access the View.
AdminModelViewExample
The following example imports a class called Person (which is described in the Model documentation). Then, the
Person class is added to the GUI using the add_view() method.
from flask.ext.diamond import Diamond, db, security
from flask.ext.diamond.administration import AdminModelView
from . import models
class my_diamond_app(Diamond):
def administration(self):
admin = super(my_diamond_app, self).administration()
admin.add_view(AdminModelView(
models.Person,
db.session,
name="Person",
4.5. GUI with Flask-Admin
27
Flask-Diamond Documentation, Release 0.4.0
category="Models")
)
When the server is launched, it provides a GUI facility for applying CRUD operations to the Person model. Due to
the use of AdminModelView, the application will now require a password before allowing anybody to create, read,
update, or delete any Person object.
The category parameter causes the GUI to put this View into the menu bar beneath the heading “Models”. The name
parameter indicates this link will be titled Person. Now you can find the Person CRUD by navigating through the
menu to Models and then to Person.
Multiple CRUD Views Inside BaseModelView
BaseModelView actually creates multiple views that provide CRUD functionality:
• Create: this view presents a form with all of the model attributes displayed as blank fields. When the fields are
populated and the form is submitted, a new model object will be created.
• List: the List view displays a paginated list of all the objects of the Model. This view also contains widgets for
editing and deleting objects.
• Edit: the Edit view is identical to the create view, except now the fields are populated by a specific model object.
When the fields are changed, the model object can be updated.
• Delete: The Delete view simply confirms whether the user wants to delete an object.
Create-List-Edit-Delete corresponds directly to Create-Read-Update-Delete.
4.5.2 Extending the CRUD
Flask-Admin makes it pretty easy to add custom functionality through Python class inheritance 3 . In the Model
documentation, the Person Model provides a birthday() method that causes the person to become one year older. The
following sections demonstrate how to expose the birthday method and create a user interface widget for calling that
method.
Exposing a new View
In addition to the basic CRUD views, new views can be created for doing other things with Models. Since the Person
class has been extended with a birthday() method, the following example enables the method to be called through the
Controller.
from flask.ext.admin import expose
class PersonModelView(AdminModelView):
@expose('/birthday/<person_id>')
def birthday(self, person_id):
the_person = models.Person.get(person_id)
the_person.birthday()
return flask.redirect(flask.url_for('.list_view'))
class my_diamond_app(Diamond):
def administration(self):
admin = super(my_diamond_app, self).administration()
3 Incidentally, Python class inheritance is the same mechanism used by Flask-Diamond for customization. Inheritance is discussed further in
writing_an_application_with_flask-diamond.
28
Chapter 4. Developer Guide
Flask-Diamond Documentation, Release 0.4.0
admin.add_view(PersonModelView(
models.Person,
db.session,
name="Person",
category="Models")
)
Adding a Widget
One simple way to add functionality to the user interface is to use Flask-Admin’s formatters to make a field into an
interactive widget. This basic pattern is demonstrated by formatting Person.age with a “birthday” button:
import jinja2
class PersonModelView(AdminModelView):
def age_formatter(self, context, model, name):
age_widget_template = "{0} <a href='{1}'>birthday!</a>"
age_widget = age_widget_template.format(
model.age,
flask.url_for(".birthday", person_id=model.id)
)
return jinja2.Markup(age_widget)
column_formatters = {
"age": age_formatter,
}
When these two PersonModelView examples are combined, the result is a user interface that can model a Person’s
birthday when a link is clicked.
ModelView Example
The following AuthModelView includes examples for overriding various fields within the model view. The full
documentation for ModelView should be consulted for more information, but this example is intended to describe how
that information may be applied within a Flask-Diamond project.
class IndividualAdmin(AuthModelView):
edit_template = 'individual_view.html'
column_list = ("name", "friend")
form_overrides = {
"upload_buffer": FileUploadField
}
form_args = {
'upload_buffer': {
'label': 'Report PDF',
'base_path': "/tmp",
}
}
4.5. GUI with Flask-Admin
29
Flask-Diamond Documentation, Release 0.4.0
More Flask-Admin
Flask-Admin is really powerful, and the best way to learn more is by reading the Flask-Admin documentation.
4.5.3 Further Reading
• See CRUD with Flask-Diamond, which describes the Create-Read-Update-Delete pattern for Models.
• See Models with SQLAlchemy for a more detailed examination of Models.
4.6 CRUD with Flask-Diamond
4.6.1 Create Read Update Delete
CRUD stands for Create, Read, Update, and Delete. The CRUD pattern complements Model-View-Controller by
providing a standard set of methods that can be applied to most types of models. CRUD acts like a simple API for
models in Flask-Diamond. The four CRUD actions describe the life-cycle of a model object:
1. First, an object is created with certain attribute values.
2. The object may be read to get the value of those object attributes.
3. The object values may be updated to update the model based on changes in the world.
4. Finally, the object is deleted to remove it from the database.
4.6.2 CRUDMixin
flask_diamond.mixins.crud.CRUDMixin, which has been adapted from Flask-Kit, will extend your model
with functions for create(), read(), update(), and delete(). The default Flask-Diamond scaffold provides
an example of CRUDMixin usage:
from flask.ext.diamond.utils.mixins import CRUDMixin
from flask.ext.diamond import db
class Person(db.Model, CRUDMixin):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(255))
age = db.Column(db.Integer)
Notice that class Person() inherits both db.Model and CRUDMixin. Now the following CRUD workflow is
possible:
myself = Person.create(name="me", age=34) # create
print "{name} is {age} years old".format(myself)
myself.update({'age': 35}) # update
print "{name} is now {age} years old".format(myself)
myself.delete()
4.6.3 Flask-Admin CRUD
Flask-Admin provides Model CRUD functionality with its BaseModelView class. BaseModelView is an extremely
powerful tool for rapidly implementing a web-based CRUD Graphical User Interface that makes it easy to create, read,
update, and delete model objects using a web browser.
30
Chapter 4. Developer Guide
Flask-Diamond Documentation, Release 0.4.0
The following application instantiates a CRUD for the Person model described above.
from flask.ext.diamond import Diamond, db
from flask.ext.diamond.administration import AdminModelView
from . import models
class my_diamond_app(Diamond):
def administration(self):
admin = super(my_diamond_app, self).administration()
admin.add_view(AdminModelView(
models.Person,
db.session,
name="Person",
category="Admin"
)
)
4.6.4 Further Reading
• See Models with SQLAlchemy for a more detailed examination of Models.
• See GUI with Flask-Admin for a more detailed examination of GUIs.
4.7 Database Schema Migration with Flask-Migrate
Any time the data model is changed, the database must be updated so that it has the right columns. Any time a table
or column is added, removed, or changed in any way, we say the database schema 4 has changed. We need to be sure
the database schema always matches the model. This common task is called schema migration, and it is handled well
by Alembic.
Flask-Diamond makes it quick and easy to rebuild the schema during development with make db, which will delete
the development database and rebuild it with all new columns matching your models. However, it’s a little drastic to
always throw everything away and start from scratch. Furthermore, when the data in your database is important, it’s
actually impossible to throw it away and start over. Luckily, there’s Flask-Migrate, which makes Alembic integration
easy so we can handle migrations smoothly.
4.7.1 Introducing Migrations
Schema migrations, which are handled using Flask-Migrate, can be used to change in-production databases by recording the minimal set of steps will make your database schema match your model. Migrations are versioned, so it is
possible to experiment with schemas before deploying them. It is also possible to roll back schemas in case something
went wrong.
4.7.2 Creating a Migration
A database migration is potentially complex, so creating one takes several steps.
1. find the location of the dev database
2. delete the development database
4 A database schema is a list of all the tables in a database, all the columns in those tables, and the data types for each column. Schemas are
often expressed using SQL CREATE statements, which is a concise way of describing exactly which tables and columns need to exist.
4.7. Database Schema Migration with Flask-Migrate
31
Flask-Diamond Documentation, Release 0.4.0
3. build the database using migrations
4. create a new migration
5. rename the file with a short summary
6. edit the migration
7. test the migration
8. done
find the location of the dev database
We will work on the dev database, which should not have any important data in it.
grep SQLALCHEMY_DATABASE_URI etc/dev.conf
delete the development database
We need to start from scratch.
rm /tmp/my-application.db
build the database using migrations
In other words, we build the database without the python Model.
make upgradedb
create a new migration
This works by comparing python model to last migration version
make migratedb
This will create a new python script within the migrations/versions subdirectory of your application module directory. There will be two functions automatically created for you: upgrade() and downgrade(). The
upgrade() function will individually add tables and columns to your old database schema until it matches your
current model. The downgrade() function is the opposite. In this manner, it is possible to “roll back” to a previous
schema.
rename the file with a short summary
cd ${MODULE}/migrations/versions
mv ${CHECKSUM}_.py ${CHECKSUM}_${SUMMARY}.py
edit the migration
• for sqlite, remove all drop_column() operations
• for sqlite, remove all create_foreign_key() operations
32
Chapter 4. Developer Guide
Flask-Diamond Documentation, Release 0.4.0
test the migration
• delete the database again (rm /tmp/daemon-dev.db)
• upgrade using migrations (make upgradedb)
• perform a new migration (make migratedb)
• verify that it is empty (i.e. all tables are reflected)
• delete the empty migration file (rm ${MODULE}/migrations/versions/${CHECKSUM}_.py)
done
The migration is ready. It can now be applied in the production environment. First, ensure you are using a configuration
file that specifies the target database you will apply the migration to. Then, invoke the schema upgrade directly.
export SETTINGS=/etc/production.conf
manage.py db upgrade
4.7.3 An Example Migration File
It is easy to see how a migration uses SQLAlchemy directly to create tables if we
examine an example.
One of the migrations that ships with Flask-Diamond is in
flask_diamond/migrations/versions/20f04b9598da_flask-diamond-020.py. In this case, the
upgrade() function adds several new columns to the user table. The file looks like this:
"""update to flask-diamond 0.2.0
Revision ID: 20f04b9598da
Revises: cf0f5b45967
Create Date: 2015-02-07 22:54:24.608403
"""
# revision identifiers, used by Alembic.
revision = '20f04b9598da'
down_revision = 'cf0f5b45967'
from alembic import op
import sqlalchemy as sa
def upgrade():
### commands auto generated by Alembic - please adjust! ###
op.add_column('user', sa.Column('current_login_at', sa.DateTime(), nullable=True))
op.add_column('user', sa.Column('current_login_ip', sa.String(length=255), nullable=True))
op.add_column('user', sa.Column('last_login_at', sa.DateTime(), nullable=True))
op.add_column('user', sa.Column('last_login_ip', sa.String(length=255), nullable=True))
op.add_column('user', sa.Column('login_count', sa.Integer(), nullable=True))
### end Alembic commands ###
def downgrade():
### commands auto generated by Alembic - please adjust! ###
op.drop_column('user', 'login_count')
op.drop_column('user', 'last_login_ip')
4.7. Database Schema Migration with Flask-Migrate
33
Flask-Diamond Documentation, Release 0.4.0
op.drop_column('user', 'last_login_at')
op.drop_column('user', 'current_login_ip')
op.drop_column('user', 'current_login_at')
### end Alembic commands ###
4.7.4 Applying a Migration
To apply a migration to the development database, enter the virtualenv and run:
make upgradedb
This will inspect your database and automatically apply migrations, in order, until it is at the latest. By default, this
applies the migration to your development database.
Migrations in Production
In order to affect the production database, you must set SETTINGS so that it points to your production configuration.
Then, you must invoke Flask-Migrate explicitly, like so:
bin/manage.py db upgrade
Displaying a Migration as SQL
It can be helpful to inspect a migration before it is applied to the database. The following command will display a
preview of the changes that will be made once a migration is applied:
bin/manage.py db upgrade --sql
4.7.5 Accessing Flask-Migrate directly
In fact, the full functionality of Flask-Migrate is easily available on the command line:
bin/manage.py db help
4.7.6 Version Control and Migrations
Because each migration has a unique checksum, and because each migration is in a separate file, it is easy to use a
version control mechanism like git to closely control your schemas.
4.8 Documentation with Sphinx
As projects grow in size, the need to create documentation increases. The Sphinx Project has put forth a very robust Python documentation solution. As a result, Flask-Diamond provides a starter template for creating your own
documentation using Sphinx.
34
Chapter 4. Developer Guide
Flask-Diamond Documentation, Release 0.4.0
4.8.1 Where are the files
You will find a starter set of documentation in the /docs folder of your project. The first file you need to edit is
called /docs/index.rst, and from there build the table of contents to describe your project. Images and media
may be placed in /docs/_static. These source files will be transformed into a documentation website that can be
browsed online.
4.8.2 Sphinx
Sphinx is a structured document generator application. As a project author, you create documents that describe your
project, and Sphinx will take care of the Table of Contents, links between documents, and all of the other parts that
make it easy for somebody to navigate the documentation. Sphinx is particularly well suited to creating documentation
websites, in which case Sphinx will automatically apply a theme to every page. The end result of using Sphinx is that
your project will have an extremely functional online documentation website.
Restructured Text
Documentation in Sphinx is written using a markup language called ReStructured Text (quickref). While this language
has some similarities to Markdown, it has many extensions that are suited to document structuring. As a result,
Restructured Text makes it easy enough to manage links between pages, make references to specific Python classes,
and add footnotes.
In my experience, the learning curve on Restructured Text is steeper than I expected. As a result, you need to persevere,
but the payoff is totally worth it. The best place to start is with the ReStructured Text documentation from the Sphinx
website.
autodoc
Sphinx can use the autodoc extension to look at your project’s file structure and determine all of the classes in your
project. This can be extremely useful for generating API documentation. Sphinx can also extract method and object
signatures, which makes it easy to describe all of the parameters for everything.
docstrings
Sphinx autodoc is also able to scan your source code for comments that have been formatted for Sphinx using Restructured Text. Here is an example taken from the flask_diamond.facets.accounts.init_accounts()
Flask-Diamond source code:
def init_accounts(self, app_models=None):
"""
Initialize Security for application.
:param kwargs: parameters that will be passed through to Flask-Security
:type kwargs: dict
:returns: None
>>> def ext_security(self):
>>>
super(MyApp, self).ext_security(confirm_register_form=CaptchaRegisterForm)
"""
The comment above will be used to create documentation by Sphinx. Special directives like :param: are used to
specify details about the documentation that autodoc cannot determine on its own.
4.8. Documentation with Sphinx
35
Flask-Diamond Documentation, Release 0.4.0
4.8.3 Building the documentation
In the project on the command line:
make docs
Output
The results of make docs will end up in var/sphinx/build. You can open that folder in your web browser to
view the documentation.
ReadTheDocs
It is easy to integrate Flask-Diamond applications with readthedocs.org due to the use of Sphinx. A special file called
.readthedocs.txt is included with the project scaffold. This file contains a reduced set of Python requirements
that may make it easier for RTD to build your project.
4.9 Email with Flask-Mail
Lots of applications need to send emails in the course of their operation. Email remains one of the best sources of
identity on the Internet today. Flask-Mail is an easy way to integrate email-sending capabilities into your application.
4.9.1 Configuration
By default, flask_diamond.facets.email is already enabled in flask_diamond.Diamond.init_app(),
so there is nothing special to do. The project created by flask-diamond has email commented out by default, so
you will have to enable this in your project’s __init__.py file.
The settings for the SMTP server are located in your configuration file. The relevant lines are these:
MAIL_SERVER = '127.0.0.1'
MAIL_PORT = 25
MAIL_USE_TLS = False
MAIL_USERNAME = None
MAIL_PASSWORD = None
You will need to set this configuration based on your particular email setup.
4.9.2 SMTP Server
In order for your application to be able to send emails, you will need access to an SMTP server. It is possible to use
an email provider such as Gmail, but be aware that you won’t be able to route a very high volume of email through
a service like that. Often times, you can use a web hosting provider for higher volumes. Since every situation is
different, you will need to track down your mail server configuration on your own.
4.10 Testing with Nose
Writing tests is an important part of building an application. Especially with dynamically typed languages such as
Python, testing is one of the only ways to determine the correctness of your implementation. Python has built the
36
Chapter 4. Developer Guide
Flask-Diamond Documentation, Release 0.4.0
concept of Unit Tests into the core library. Unit Testing is a technique for validating units of your program by making
assertions about the behaviour of that code. If any assertions turn out to be false, then you know your code isn’t correct.
4.10.1 Nose
In the interest of making test as automatic as possible, Flask-Diamond uses Nose for test discovery, which will find
and run all your tests without having to create a test harness. As an application becomes more developed, it may
become necessary to build a test harness for the application. However, at the start of application development, it is
usually easier to use test discovery in order to iterate faster.
Nose will automatically search through the /tests folder for any files starting with the name “test” that have functions in them that also start with “test”.
4.10.2 Running Tests
It is possible to invoke the testing subsystem from the command line. The following different testing methods are
available in Flask-Diamond:
Run every test
Find every test and run it.
make test
Run individual tests
Run tests identified with decorator @attr("single"). These “single” tests can be used to make testing much
faster by skipping all of the other tests.
make single
The following code snippet contains a simple test with the single attribute decorator applied to it.
from nose.plugins.attrib import attr
from flask.ext.testing import TestCase
from flask.ext.diamond.mixins.testing import DiamondTestCaseMixin
class BasicTestCase(DiamondTestCaseMixin, TestCase):
@attr("single")
def test_basic(self):
assert True
Automatically run individual tests
This functionality will watch the project folder for files to change. When a file has changed, it will re-run tests identified
with @attr("single"). This feature is designed to make it very quick to get feedback on the performance of your
code.
make watch
4.10. Testing with Nose
37
Flask-Diamond Documentation, Release 0.4.0
4.10.3 xUnit
It is possible to automatically interpret the results of testing using the xUnit framework. Nose xUnit output can permit
tools like Jenkins CI, Travis CI, or Atlassian Bamboo to capture the results of testing.
4.11 Users Accounts with Flask-Security
User accounts are a common requirement for many applications. Another common requirement is Roles, which can
be used to grant certain users access to specific functions. Both Users and Roles are provided in Flask-Diamond by
Flask-Security, which provides a nice interface for controlling these models.
4.11.1 User and Role Models
Flask-Diamond is already set up with flask_diamond.models.user and flask_diamond.models.role,
which provide everything needed for a simple setup.
You will notice in your application that
models/__init__.py then imports these classes from Flask-Diamond. In this manner, your application will
incorporate these models into its own schema.
4.11.2 Overloading the User Model
With an application of moderate complexity, it may be necessary to store additional user data, and certain data may just
be simple to put in the User model directly. The following code snippet describes an init_security() function
that can be used to implement your own User model.
def init_security(self):
self.super(app_models=models)
With that in place, ensure models__init__.py imports your own User model instead of importing from FlaskDiamond.
4.11.3 Flask-Admin Integration
You can use user accounts in lots of ways, but one common pattern for Users is to create a
password-protected user interface. To make this easier, the Flask-Diamond scaffold includes templates in
views/administration/templates/security that permit you to customize the look of login, password
maintenance, account registration, and password reset. The templates already inherit from Flask-Admin, but by editing
the templates in your project, you can customize them to other scenarios too.
4.12 Debugging a Flask-Diamond Application
To simplify debugging, Flask-Diamond provides a basic setup for logging so that your application can write trace data
to a file for your inspection. Flask-Diamond also integrates Flask-DebugToolbar to provide a powerful debugger shell
directly in the interface.
4.12.1 Logs
Flask-Diamond creates a logging object during initialization. You can write log messages to this object with the
following basic code:
38
Chapter 4. Developer Guide
Flask-Diamond Documentation, Release 0.4.0
flask.current_app.logger.debug("this is a debug-level message")
flask.current_app.logger.warn("important! this is a warning message")
The destination for log files is controlled in the configuration file. During development, dev.conf will write log
messages to the var/logs path of your project.
Log Level
During debugging, it is sometimes useful to get extra information about your application while it is running. The log
level is used to control how critical logging is. When the level is DEBUG, then all messages are printed - this can be
verbose. When the level is INFO, then debugging messages are not printed at all, but general information messages
are. When the level is WARN, then only important messages are printed. This level may be suitable for production.
4.12.2 DebugToolbar
Flask-DebugToolbar is a useful web gadget that can help developers to diagnose problems within the browser. In
practice, you may end up doing most of your development in a terminal, but the Debug Toolbar can nevertheless be
handy for casual projects.
In the application configuration file, whenever DEBUG=True the DebugToolbar will be active. By default, the
development configuration enables debugtoolbar whereas the production configuration disables it. It is possible to completely remove the DebugToolbar by ensuring the debugger extension is not loaded at all during
flask_diamond.Diamond.init_app().
4.12. Debugging a Flask-Diamond Application
39
Flask-Diamond Documentation, Release 0.4.0
40
Chapter 4. Developer Guide
CHAPTER 5
User Guide
The User Guide topics are for managing and installing a Flask-Diamond application. In particular, IT Ops and Deployment Engineers will benefit from this section.
5.1 Requirements Management with virtualenv
The preferred way to manage your Python requirements is with virtualenv. The preferred way to manage virtualenvs
is with virtualenvwrapper, which provides a regularized interface for creating and using virtualenvs.
When you install your Flask-Diamond application inside a virtualenv, you are able to “freeze” the state of your installed
Python libraries. This way, your application will never suffer from broken requirements due to a system-wide upgrade.
This document describes the typical workflow for using virtualenv to manage a Flask-Diamond project.
5.1.1 Pre-requisites
You need to install the minimum System Requirements in order to have the necessary tools for this process. It is
assumed that you now have workon and mkvirtualenv available. If you cannot call these commands in a terminal,
then you should double-check your System Requirements.
5.1.2 Making a New virtualenv
The way to initialize a new virtualenv is with mkvirtualenv, which is described on the mkvirtualenv documentation. The following example demonstrates creating a virtualenv called my-diamond-app.
$ mkvirtualenv my-diamond-app
New python executable in my-diamond-app/bin/python2.7
Also creating executable in my-diamond-app/bin/python
Installing setuptools, pip...done.
(my-diamond-app) $
Upon creating the virtualenv, it will be activated and your shell prompt changes to include your project name as a
prefix. You can verify that you are inside the virtualenv by echoing an environment variable to the screen:
(my-diamond-app) $ echo $VIRTUAL_ENV
~/.virtualenvs/my-diamond-app
41
Flask-Diamond Documentation, Release 0.4.0
5.1.3 Using it
When you need to work on your project, you must activate your project’s virtualenv using workon. After calling
workon, your shell’s search path will be updated so that scripts from your virtualenv will be called before any
globally installed scripts.
$ workon my-diamond-app
(my-diamond-app) $
In order to leave the virtualenv and return to a normal shell, use deactivate.
(my-diamond-app) $ deactivate
$
5.1.4 pip and Installation
When you use pip inside your virtualenv, it will automatically install packages locally, instead of installing them at
the system level. This way, it’s easy to install anything without needing root access. In the following example, we are
inside our virtualenv and we want to upgrade pip:
(my-diamond-app) $ pip install --force -U pip
Collecting pip
Downloading pip-7.1.0-py2.py3-none-any.whl (1.1MB)
100% || 1.1MB 172kB/s
Installing collected packages: pip
Successfully installed pip-7.1.0
(my-diamond-app) $
5.1.5 Freezing Python Requirements
pip provides a handy mechanism for printing all of the installed libraries, along with their versions. When called
within your virtualenv, it produces a snapshot of all your project requirements so you can easily re-install them later.
(my-diamond-app) $ pip freeze
Jinja2==2.7.3
MarkupSafe==0.23
mr.bob==0.1.1
requests==2.7.0
virtualenv==1.11.6
virtualenvwrapper==4.2
(my-diamond-app) $
You can also store your requirements in a requirements file.
(my-diamond-app) $ pip freeze > requirements.txt
5.1.6 Makefile support
By default, Flask-Diamond provides make install, which will use requirements.txt to install your project’s prerequisites automatically.
42
Chapter 5. User Guide
Flask-Diamond Documentation, Release 0.4.0
5.2 Configuration Explanation
The use of configuration files permits your application to easily adapt to multiple environments. Often times, different
systems will use different path structures, user accounts, database configurations, and TCP ports. Flask-Diamond
implements the practices suggested by Flask 0.10, and by default stores these config files in the ./etc folder of your
project.
5.2.1 The SETTINGS Environment Variable
Flask-Diamond will load its configuration from whatever file is referenced by the $SETTINGS environment variable.
You can use $SETTINGS to easily manage several profiles for your application. The following example demonstrates
choosing the development profile stored in dev.conf.
export SETTINGS=$PWD/etc/dev.conf
Another common way to control $SETTINGS is to use it as a prefix in front of a command. In the following example,
the script bin/manage.py is invoked with the dev.conf profile to start the embedded HTTP server:
SETTINGS=$PWD/etc/dev.conf bin/manage.py server
To start the server with the production.conf environment:
SETTINGS=$PWD/etc/production.conf bin/manage.py server
5.2.2 Examples of Configurations
Flask-Diamond ships with a few configuration profiles to get you started:
dev.conf
The development environment is typically used on your developer workstation. You probably have root access to the
machine. Any databases are probably temporary in nature, and exist mostly for testing purposes.
production.conf
The production environment is typically your front-facing web server (a “live server”). In this case, the application
is probably not running as root. In fact, you may not even have root access to this machine. Thus, you must choose
filenames for logging output that are owned by the application user’s account. The production database is also likely
to have different permissions, and unlike the development database, the production database probably has important
information on it that you want to protect.
testing.conf
For testing purposes, there is a special configuration that writes to a temporary database that is created and destroyed
during tests.
5.2. Configuration Explanation
43
Flask-Diamond Documentation, Release 0.4.0
5.2.3 Makefile Support
If you inspect the Makefile, you will see that $SETTINGS=$PWD/etc/dev.conf appears before most commands. Most cases will use dev.conf by default in order to protect against accidentally performing tasks upon the
production database. Those prefixes are hardcoded so that a command like make db (which resets the database from
scratch) cannot easily be applied to the production database.
5.2.4 Flask-Diamond Configuration Variables
By default, Flask-Diamond expects the following variables to be present within a configuration file.
Project
The project is configured with the following directives.
PROJECT_NAME = "Flask-Diamond"
PORT = 5028
LOG = "var/log/dev.log"
LOG_LEVEL = "DEBUG"
SQLALCHEMY_DATABASE_URI = "sqlite:////tmp/flask_diamond-dev.db"
SECRET_KEY = "av^\x81\x03\xd7\xd1\xbd\x92~b\x00\xe8\xf7n9\x0e\xf8i\xdb\xba'\xa9\xea"
BASE_URL = "http://flask-diamond.org/my-diamond-app"
• PROJECT_NAME: the human-readable name of the project
• PORT: which TCP port will the HTTP server listen on?
• LOG: the filename to log messages to
• LOG_LEVEL: control the verbosity of logging output; DEBUG prints everything, INFO prints less, and WARN
will only display problems.
• SQLALCHEMY_DATABASE_URI: a URI that points to your database. See Flask-SQLAlchemy for more examples.
• SECRET_KEY: a randomly-generated string that you created during scaffolding
• BASE_URL: the canonical name for your web application
Debugging
Debugging instructs the application to print extra information during operation. For example, there may be more
verbose logging and it may be possible to inspect the application internals. All of this is helpful during development,
but can be extremely dangerous in production.
DEBUG = False
DEBUG_TOOLBAR = True
DEBUG_TB_INTERCEPT_REDIRECTS = False
• DEBUG: when debugging is enabled, Flask produces tracebacks when an exception is encountered.
• DEBUG_TOOLBAR: whether to include Flask-DebugToolbar, which is a helpful in-browser debugging widget.
• DEBUG_TB_INTERCEPT_REDIRECTS: it is possible to inject the debug toolbar before URL redirects, which
can be helpful for isolating routing problems.
44
Chapter 5. User Guide
Flask-Diamond Documentation, Release 0.4.0
Accounts and Security
Flask-Security provides an integrated platform of account security features, and Flask-Diamond incorporates most of
its functionality. The following directives control Flask-Security.
SECURITY_PASSWORD_SALT = "aIf8ObrvtSTkIIGd"
SECURITY_POST_LOGIN_VIEW = "/admin"
SECURITY_PASSWORD_HASH = 'sha256_crypt'
SECURITY_URL_PREFIX = '/user'
SECURITY_CHANGEABLE = True
SECURITY_SEND_PASSWORD_CHANGE_EMAIL = False
SECURITY_CONFIRMABLE = False
SECURITY_REGISTERABLE = False
SECURITY_RECOVERABLE = False
SECURITY_TRACKABLE = True
SECURITY_EMAIL_SENDER = "[email protected]"
• SECURITY_PASSWORD_SALT: The salt is a random string you generated during scaffolding. This is used to
encrypt the password database.
• SECURITY_POST_LOGIN_VIEW: the name of the view to redirect to upon a successful login
• SECURITY_PASSWORD_HASH: the name of the hashing algorithm to use for passwords. sha256_crypt is
recommended.
• SECURITY_URL_PREFIX: Change the URL prefix to make all account-related facilities appear as a subdirectory (like /user).
• SECURITY_CHANGEABLE: Can users change their own passwords?
• SECURITY_SEND_PASSWORD_CHANGE_EMAIL: Should users be notified by email when their password is
changed?
• SECURITY_CONFIRMABLE: Must users confirm their email address in order to activate their account?
• SECURITY_REGISTERABLE: Is self-registration allowed?
• SECURITY_RECOVERABLE: Can a user reset their password if they have forgotten it?
• SECURITY_TRACKABLE: Does the User model include fields for recording User account history? By default,
Flask-Diamond provides these fields. See the Flask-Security docs for more information about this.
• SECURITY_EMAIL_SENDER: What is the email address that security messages should be sent from?
ReCAPTCHA
Flask-Captcha provides a quick mechanism for ensuring your application is used by people instead of bots. You may
recognize CAPTCHA as the squiggly letters and numbers that you must type into a text box. In order to get started
with CAPTCHA and ReCAPTCHA, you must create a free account with their service.
RECAPTCHA_PUBLIC_KEY = '0000_00000000000000000000000000000000000'
RECAPTCHA_PRIVATE_KEY = '0000_00000000000000000000000000000000000'
• RECAPTCHA_PUBLIC_KEY: The ReCAPTCHA online service will provide you with a public key, which will
be included with your web application.
• RECAPTCHA_PRIVATE_KEY: ReCAPTCHA also provides a private key, but this one must be kept secret. You
will enter it in this configuration file, but nowhere else.
5.2. Configuration Explanation
45
Flask-Diamond Documentation, Release 0.4.0
Flask-Mail
The simplest way for your application to send email is using Flask-Mail, which makes it pretty easy to create and send
emails.
MAIL_SERVER = '127.0.0.1'
MAIL_PORT = 25
MAIL_USE_TLS = False
MAIL_USERNAME = None
MAIL_PASSWORD = None
• MAIL_SERVER: the hostname or IP address of your SMTP server
• MAIL_PORT: the port used by your SMTP server. Usually, this is 25 or 465.
• MAIL_USE_TLS: If the server supports or requires encryption (with TLS), then set this to True
• MAIL_USERNAME: If you must provide authentication information to your server in order to send email through
it, then provide the username here.
• MAIL_PASSWORD: As with the username, provide the password here if it is required.
Celery
Celery is a job queue that has been integrated into Flask-Diamond so that you create background tasks for any operations that take a while to complete. Typically, you will want your application to respond to requests within 100ms,
but when this is not possible, you can achieve a rapid response by queueing the slow operation so that it executes
separately. This way, it is still possible to respond to requests quickly enough that nobody will notice.
CELERY_BROKER_URL = 'sqla+sqlite:///var/db/celerydb.sqlite'
CELERY_RESULT_BACKEND = 'db+sqlite:///var/db/results.sqlite'
• CELERY_BROKER_URL: the URL pointing to a database connection. This is like the SQLAlchemy URI, but
different enough that you should consult the documentation.
• CELERY_RESULT_BACKEND: Celery is able to store job results in a separate database, and for certain types
of jobs, this is recommended. The URI here is similar to but different from the CELERY_BROKER_URL.
5.3 Makefile Explanation
The Makefile that ships with Flask-Diamond by default includes a number of targets that address several common
tasks throughout the life cycle of a project. The way to use the Makefile is with the make command. Thus, to install
the project with make, you’d invoke make install.
During development, the Makefile is one of the primary ways for you to interact with your project. You may find
yourself running make db server or perhaps make single with some regularity. It is recommended to become
familiar with the Flask-Diamond Makefile.
5.3.1 Integration
These targets control project builds.
• install: Use setup.py to install the project (typically inside a virtualenv).
• clean: Delete all of the temporary files created by install.
• docs: Use Sphinx to render the documentation in etc/sphinx.
46
Chapter 5. User Guide
Flask-Diamond Documentation, Release 0.4.0
5.3.2 Development
These targets are used to run the application with the dev.conf profile.
• server: Invoke the HTTP server in debug mode with dev.conf
• shell: Enter a python (or ipython) shell within the virtualenv.
• notebook: Use ipython notebook, if installed, to inspect the application.
5.3.3 Testing
These targets are used to run automated tests.
• test: Run all of the tests using nosetests.
• single: Run only tests marked with the @attr("single") decorator.
• watch: Enter a loop that watches for any project source code to be changed, and then automatically run any
tests marked with the @attr("single") decorator.
5.3.4 Databases
These targets control the database. By default these use the dev.conf profile so as to avoid inadvertently changing
the production database.
• db: drop the database, re-create the database, and populate the database with starter values.
• migratedb: when the data model schema has changed, use migratedb to create a new data migration.
• upgradedb: apply all data migrations, in order, until the database is up to date.
5.4 manage.py Explanation
Many applications will want to expose some functionality through a command line interface, and bin/manage.py
provides an easy way to accomplish this. For example:
• certain administrative tasks could be triggered from the command line
• other tasks can be automated using a tool like cron
Many of the targets within the Flask-Diamond Makefile are actually wrappers for manage.py, but you can invoke it
manually on the command line like so:
SETTINGS=$PWD/etc/conf/dev.conf bin/manage.py runserver
The following commands come with Flask-Diamond by default.
5.4.1 Commands
• shell: Launch the Python REPL (or iPython if installed) using Flask-Script. By default, the following objects
will be imported into the namespace:
– app: your app’s Flask-Diamond object
– db: your app’s database object
– model: your app’s model
5.4. manage.py Explanation
47
Flask-Diamond Documentation, Release 0.4.0
• runserver: Launch your application’s HTTP server. When runserver is invoked, it will bind to
localhost. The PORT your application listens on is defined in the Configuration Explanation.
• publicserver: Like runserver but public. This causes the server to bind to 0.0.0.0 so that remote
hosts can connect to your application. This is intended for development purposes, and is not recommended for
deployment. See Web Services with WSGI for more information about running a public web service.
• db: This command acts as the entry point for Flask-Migrate. The subcommands available, taken directly from
the command output, are:
– upgrade: Upgrade to a later version
– heads: Show current available heads in the script directory
– show: Show the revision denoted by the given symbol.
– migrate: Alias for ‘revision –autogenerate’
– stamp: ‘stamp’ the revision table with the given revision; don’t run any migrations
– current: Display the current revision for each database.
– merge: Merge two revisions together. Creates a new migration file
– init: Generates a new migration
– downgrade: Revert to a previous version
– branches: Show current branch points
– history: List changeset scripts in chronological order.
– revision: Create a new revision file.
• useradd: Add a user to the users database via Flask-Security. This accepts the following arguments:
– email: (required)
– password: (required)
– admin: True/False Should this user have the Admin role?
• userdel: Delete a user from the users database.
• init_db: Drop the existing database using Flask-SQLAlchemy and re-create it. This obviously destroys
anything in the database, resetting it to its original state.
• populate_db: Sometimes, it is convenient to populate the database with a starting set of objects. The
populate_db command is a handy opportunity to ship some data with your project.
5.5 Web Services with WSGI
For deploying your application in a production environment, you will probably end up using a WSGI application
server like uwsgi or gunicorn. By default, Flask-Diamond will install gunicorn as a requirement.
5.5.1 System Start-up
Under most circumstances, you will want to automatically run the application server when the host boots. This is
going to be different for every host, but an example demonstrates launching gunicorn via Ubuntu upstart:
48
Chapter 5. User Guide
Flask-Diamond Documentation, Release 0.4.0
#!upstart
description "flask-diamond daemon"
env USER=flask-diamond
env SETTINGS=/etc/flask-diamond.conf
start on runlevel [2345]
stop on runlevel [06]
respawn
exec start-stop-daemon --start \
--make-pidfile \
--pidfile /var/run/$USER-daemon.pid \
--chuid $USER \
--exec /var/lib/$USER/.virtualenvs/$USER/bin/gunicorn -- \
--workers 2 \
--bind 0.0.0.0:5000 \
--user $USER \
--chdir /var/lib/$USER \
--log-file /var/lib/$USER/gunicorn-error.log \
--access-logfile /var/lib/$USER/gunicorn-access.log \
--pid /var/run/$USER-daemon.pid \
--daemon \
flask_diamond.wsgi:app
This demonstrates several important principles:
• setting the configuration file that will control the application server
• launching the application server from inside the Python virtual environment
5.5.2 Reverse Proxy
You probably want to keep your application server behind a firewall, so a common pattern for deploying FlaskDiamond applications relies upon a reverse proxy. There is a good Digital Ocean tutorial for setting up a reverse proxy
with either nginx or apache.
5.5.3 Puppet-Diamond
For scaling up deployment, it is recommended to use an automation solution like Puppet or Chef. Flask-Diamond is
particularly easy to deploy with Puppet-Diamond, which will simplify the management of the host configurations as
well as application deployment.
5.5.4 Embedded Server
Flask-Diamond provides an embedded web server with bin/manage.py and bin/runserver.py for simple
deployments, like development and debugging. This is not recommended for production use. However, when paired
with a reverse proxy, this is actually good enough to handle a surprising amount of traffic.
5.5. Web Services with WSGI
49
Flask-Diamond Documentation, Release 0.4.0
5.6 IT Operations with Fabric
There is frequently a split between the application development environment and the live deployment environment.
When the application ends up running on a remote host while you are doing your work on a workstation, it can be
helpful to simplify remote system operations. Flask-Diamond uses Fabric to make it pretty easy to invoke system
functions from the command line.
5.6.1 Using Fabric
To use the Flask-Diamond Fabric functionality, navigate to the root directory of the project and issue the following
command:
fab help
This will list all of the available commands.
5.6.2 Flask-Diamond Fabric Commands
By default, Flask-Diamond provides a fabfile.py with the scaffold with the following functionality:
• rsync: copy files directly from the working directory to the remote host
• pull: on the remote host, execute git pull in the application directory
• setup: run make install on the remote host
• ipython: enter an ipython shell on the remote host
• shell: open a bash shell on the remote host
• restart: restart the remote application server
• nginx_restart: restert the remote web server
• logs: view the application logs
5.6.3 Customizing Fabric
Because all systems are different, it is not too likely that all of the commands in fabfily.py will work. However,
this at least provides a starting point.
50
Chapter 5. User Guide
CHAPTER 6
About Flask-Diamond
6.1 Libraries Included in Flask-Diamond
Flask-Diamond pulls from many different Flask extensions, which are all listed in this document. A significant factor
for inclusion with Flask-Diamond is the existence of good documentation. Most of the following libraries therefore
provide extensive documentation that can help you to understand everything in greater detail.
6.1.1 Database/Model
• Flask-SQLAlchemy: “Flask-SQLAlchemy is an extension for Flask that adds support for SQLAlchemy to your
application. It requires SQLAlchemy 0.6 or higher. It aims to simplify using SQLAlchemy with Flask by
providing useful defaults and extra helpers that make it easier to accomplish common tasks.”
• Flask-Migrate: “Flask-Migrate is an extension that handles SQLAlchemy database migrations for Flask applications using Alembic. The database operations are provided as command line arguments for Flask-Script.”
• Flask-Marshmallow: “Flask-Marshmallow is a thin integration layer for Flask (a Python web framework) and
marshmallow (an object serialization/deserialization library) that adds additional features to marshmallow, including URL and Hyperlinks fields for HATEOAS-ready APIs. It also (optionally) integrates with FlaskSQLAlchemy.”
6.1.2 Development
• Flask-Testing: “The Flask-Testing extension provides unit testing utilities for Flask.”
• Flask-DebugToolbar: “This extension adds a toolbar overlay to Flask applications containing useful information
for debugging.”
• Flask-DbShell: “The extension provides facilites for implementing Django-like ./manage.py dbshell command”
• Flask-Script: “The Flask-Script extension provides support for writing external scripts in Flask. This includes
running a development server, a customised Python shell, scripts to set up your database, cronjobs, and other
command-line tasks that belong outside the web application itself.”
6.1.3 Security
• Flask-Security: “Flask-Security allows you to quickly add common security mechanisms to your Flask application.”
51
Flask-Diamond Documentation, Release 0.4.0
• Flask-Login: “Flask-Login provides user session management for Flask. It handles the common tasks of logging
in, logging out, and remembering your users’ sessions over extended periods of time.”
6.1.4 Doing Stuff
• Flask-Celery-Helper: “Celery support for Flask without breaking PyCharm inspections.”
• Flask-Mail: “The Flask-Mail extension provides a simple interface to set up SMTP with your Flask application
and to send messages from your views and scripts.”
6.1.5 Interfaces
• Flask-Admin: “In a world of micro-services and APIs, Flask-Admin solves the boring problem of building an
admin interface on top of an existing data model. With little effort, it lets you manage your web service’s data
through a user-friendly interface.”
• Flask-RESTful: “Flask-RESTful is an extension for Flask that adds support for quickly building REST APIs.
It is a lightweight abstraction that works with your existing ORM/libraries. Flask-RESTful encourages best
practices with minimal setup. If you are familiar with Flask, Flask-RESTful should be easy to pick up.”
• Flask-WTF: “Flask-WTF offers simple integration with WTForms.”
6.1.6 Presentation
• Flask-Assets: “Flask-Assets helps you to integrate webassets into your Flask application.”
• Flask-Markdown: “Flask-Markdown adds support for Markdown to your Flask application. There is little to no
documentation for it, but it works just the same as markdown would normally.”
6.2 Diagram of Libraries
Flask-Diamond is composed of many other libraries. The following diagram is an effort to describe how these modules
are organized. The SVG diagram of Flask-Diamond libraries is also available for download.
52
Chapter 6. About Flask-Diamond
Flask-Diamond Documentation, Release 0.4.0
6.2. Diagram of Libraries
53
Flask-Diamond Documentation, Release 0.4.0
6.3 How to Contribute to the Project
Flask-Diamond welcomes contributions from everybody, and there are several ways you can help! The first step is
always to clone the project repository using git. If you haven’t done this yet, then do it now. Then, give the rest of this
document a read for some specific ideas about contributing.
6.3.1 Implement your favourite features
If you know a feature you’d like to code in order to help with Flask-Diamond, then the easiest way to help is by
submitting a pull request to Flask-Diamond on GitHub. From your perspective, this requires no commitment and there
is no barrier preventing you from contributing to Flask-Diamond today.
6.3.2 Help with the documentation
Project documentation is one of the most important aspects of an open source project. You can help immensely by
editing the current documentation for clarity. You can find the documentation in the Flask-Diamond repository, which
you can modify by submitting a pull request.
6.3.3 Help with an existing issue
Another way you can contribute is by working directly upon issues that have been submitted by the community using
the Issue Tracker. This is more advanced than simply implementing a new feature, because the issue may specify
acceptance criteria. It is recommended that you coordinate with project members before working on an issue. The
easiest way to contact the team is through the Issue Tracker itself, because each issue has a comment thread associated
with it.
6.3.4 Become a project developer
If you have proven yourself to consistently deliver great work on Flask-Diamond, then you should join the development
team! The team uses a Project Kanban to coordinate its development efforts. In order to join the team, you must be
familiar with Agile-Diamond, which is the project management framework used for working on Flask-Diamond. Other
than that, you must simply open an issue in the Issue Tracker requesting to become a team member.
6.3.5 On rejection...
It should be stated up-front: not every pull request can be merged. We still have to review everything, and sometimes,
we cannot accept a pull request. To whatever extent it’s possible, we will explain using the comment features of
GitHub. There is an art to creating masterful pull requests, and sometimes beginners have to learn more before they
can be good at it. We will help you, but you must realize that this becomes a cost to the team. Please do not take it
personally; we were all beginners at some point!
6.4 Philosophy of Flask-Diamond
Flask-Diamond provides a path that can guide your thought and development. Flask-Diamond is the road that leads
to other ideas.
The following principles serve to guide the development of Flask-Diamond.
54
Chapter 6. About Flask-Diamond
Flask-Diamond Documentation, Release 0.4.0
6.4.1 Inheritance
Flask-Diamond is primarily configured via Pythonic Inheritance. Your main application object will inherit from FlaskDiamond, and any functions you wish to customize must be overridden in order to change their behavior.
6.4.2 Economy
There are tons of libraries wrapped up in Flask-Diamond. If something has been done well by somebody else, then it
is always preferable to leverage that work instead of re-building an unnecessary component.
6.4.3 Stable
Flask-Diamond versions are tied closely to specific versions of third-party libraries. When you stick with a specific
version of Flask-Diamond, you can lock the version of third-party libraries too. The goal is to prevent any requirements
from changing accidentally so that your application will be more resistant to code rot and API breakage.
6.4.4 Decomposable
Because third-party libraries are constantly changing, it is sometimes desirable to upgrade just one library without
upgrading anything else. Flask-Diamond is built atop the Flask ecosystem, which is architecturally decomposable.
Thus, extensions may be upgraded individually.
6.4.5 Data-centric
Flask-Diamond was originally built to support the research objectives of Ian Dennis Miller. Through his work on
memes and social networks, Ian regularly needed to build lightweight API access to big data sets. Due to the precise
nature of the SQL queries needed, a powerful standalone ORM like SQLAlchemy was preferred over the Django
approach of bundling the ORM with the web platform. Thus, Flask-Diamond is suitable for projects that require raw
access to SQL queries.
6.4.6 Sensible
Flask-Diamond is pretty sensible about the defaults it presents. A lot of decisions have already been made in the
service of delivering a functioning application out-of-the-box. The goal is to enable a focus upon the unique parts of
your application, rather than the common tasks that most applications need anyway.
6.5 Change Log
This file contains a summary of major changes to Flask-Diamond.
6.5.1 0.3.0
2016-01-21
• a new application startup procedure based on extensions
• putting skels into project
• integrate wsgi launcher
6.5. Change Log
55
Flask-Diamond Documentation, Release 0.4.0
• refine questions, add version to project config
• making readme generate from a template
• use alabaster doc theme
• refactor extensions into separate namespace
• added super method, fixing templates
• removing Individual from the skeleton
• refactoring mixins
• simplify views, create separate skel
• added change log document
• documented API creation
• diagram of libraries
• wrote sphinx docs
• wrote email document, testing document
• wrote about user accounts, project diagram
• wrote wsgi, fabric
6.5.2 0.2.16
2015-01-21
• putting skels into project
6.5.3 0.2.15
2015-08-05
• switch theme to be flask-esque
• adding new documentation stubs and restructuring TOC
• added build details to footer
• created quick-start
• stubbed several new documents
• gather git hash using a different command
• wrote scaffolding explanation
• wrote philosophy and some of the learning section
• starting GUIs with Flask-Admin
• remove sqlite from requirements for documentation build
• separate requirements from installation
• remove pysqlite2 requirement
• added relationship examples to models, rounded out gui examples
• finishing Views documentation
56
Chapter 6. About Flask-Diamond
Flask-Diamond Documentation, Release 0.4.0
• update migration process
6.5.4 0.2.13
2015-07-30
• controlling documentation more closely
• migrating markdown documentation to sphinx
• inter-linking github, pypi, and readthedocs
• add resources to REST api before calling init_app
6.5.5 0.2.12
2015-07-30
• This release was used to debug packaging and documentation.
6.5.6 0.2.11
2015-07-30
• This release was used to debug packaging and documentation.
6.5.7 0.2.10
2015-07-29
• separate models into submodules
• remove backref on user roles to permit easier inheritance and overloading of the User model
• store requirements in separate file
• split documentation into smaller files
6.5.8 0.2.9
2015-07-08
• admin views can be turned off
• admin views can be toggled
• Create Dependencies.md
6.5.9 0.2.8
2015-06-01
• Update manage.py
6.5. Change Log
57
Flask-Diamond Documentation, Release 0.4.0
6.5.10 0.2.7
2015-05-13
• include marshmallow mixin
• loads() from unmarshalled data
• load(), loads(), loadf()
6.5.11 0.2.6
2015-04-24
• hardcoding alembic because the latest version does not parse correctly in FlaskMigrate
• can disable admin views
6.5.12 0.2.5
2015-03-20
• useradd and userdel
• migrate conf files into subdir
• decent isolation of blueprints, but weirdness with security
6.5.13 0.2.4
2015-03-15
• bump flask-admin version
• fixed user create with password
• fixed layout of login page
6.5.14 0.2.3
2015-03-03
• mrbob
6.5.15 0.2.2
2015-03-03
• bump requirements
• reduce required libraries
58
Chapter 6. About Flask-Diamond
Flask-Diamond Documentation, Release 0.4.0
6.5.16 0.2.1
2015-02-17
• delayed commit in CRUD
• default repr in CRUD
• bump flask script and SQLAlchemy
6.5.17 0.2.0
2015-02-07
• use latest Flask-Migrate==1.3.0
• move user management into user model
• remove unnecessary variables
• reorganize
• meta script helps keep skels aligned
• trying to get migrations neat
• working meta-build
• simpler test fixture
• using relative paths
• scaffolding util
• repair manifest
• fixing paths for databases
• tweak documentation
• automatically sync github pages with API documentation
• API more prominent
• autosync documentation
• include description in sphinx main document
• documented every method
6.5.18 0.1.10
2015-02-04
• freeze versions of other dependencies
• update docs
6.5.19 0.1.9
2015-01-25
• PEP8 for setup, migrate a few Flask libraries into the core
6.5. Change Log
59
Flask-Diamond Documentation, Release 0.4.0
6.5.20 0.1.8
2014-11-19
• it is possible to contol the AdminIndexView during app creation
6.5.21 0.1.7
2014-06-29
• use new class instantiation for flask-mail
6.5.22 0.1.6
2014-06-23
• remove ipython dependency
6.5.23 0.1.5
2014-06-16
• more robust user creation
• admin object local to entire package
• update flask-admin dependency
6.5.24 0.1.3
2014-03-29
• do not require a specific version of distribute
• include webassets
6.5.25 0.1.2
2014-03-22
• correct auth mixin ordering
• load/save mixins
6.5.26 0.1.1
2014-03-20
• split error handlers and request handlers
• support changeable passwords
• removed hardcoded config options
• code annotation
60
Chapter 6. About Flask-Diamond
Flask-Diamond Documentation, Release 0.4.0
• steps towards PEP8
• following Flask capitalization conventions
• account functions are behind /user URL
• CRUD create() may defer commit
6.5.27 0.1
2014-03-06
• Initial public release.
6.6 License
The MIT License (MIT)
Flask-Diamond Copyright (c) 2016 Ian Dennis Miller
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
6.6. License
61
Flask-Diamond Documentation, Release 0.4.0
62
Chapter 6. About Flask-Diamond
CHAPTER 7
API Reference
7.1 API
This documentation is for Flask-Diamond 0.4.0.
7.1.1 Diamond object
class flask_diamond.Diamond(name=None)
A Diamond application.
Parameters app (Flask) – a Flask app that you created on your own
Returns None
facet(extension_name, **kwargs)
initialize an extension
init_accounts()
initialize accounts with the User and Role classes imported from .models
init_administration()
Initialize admin interface
super(extension_name, **kwargs)
invoke the initialization method for the superclass
ex: self.super(“administration”)
teardown(exception)
Remove any persistent connections during application context teardown.
Returns None
flask_diamond.create_app()
7.1.2 models
models.user
class flask_diamond.models.user.User(**kwargs)
Bases:
flask_sqlalchemy.Model,
flask_security.core.UserMixin,
flask_diamond.mixins.crud.CRUDMixin, flask_diamond.mixins.marshmallow.MarshmallowMixin
63
Flask-Diamond Documentation, Release 0.4.0
active
boolean – whether the user account is active
classmethod add_admin_user(name=’admin’, email=’[email protected]’, password=’aaa’)
classmethod add_guest_user(name=’guest’, email=’[email protected]’, password=’guest’)
add_role(role_name)
update a User account so that it includes a new Role
Parameters role_name (string) – the name of the Role to add
confirm()
update a User account so that login is permitted
Returns None
confirmed_at
datetime – when the user account was confirmed
current_login_at
datetime – the time of the current login, if any
current_login_ip
string – the IP address of the current login
email
string – email address
id
integer – primary key
last_login_at
datetime – the time of the most recent login
last_login_ip
string – the IP address of the previous login
login_count
integer – the number of times this account been accessed
name
string – user name
password
password – the users’s password
classmethod register(name, email, password, confirmed=False, roles=None)
Create a new user account.
Parameters
• name (string) – the name of the account
• email (string) – the email address used to identify the account
• password (string) – the plaintext password for the account
• confirmed (boolean) – whether to confirm the account immediately
• roles (list(string)) – a list containing the names of the Roles for this User
classmethod rm_system_users()
remove default system users
Returns None
64
Chapter 7. API Reference
Flask-Diamond Documentation, Release 0.4.0
roles
class flask_diamond.models.user.UserSchema(obj=None,
extra=None,
only=None,
exclude=None,
prefix=u’‘,
strict=False,
many=False,
skip_missing=False,
context=None)
Bases: flask_marshmallow.Schema
class Meta
additional = (‘id’, ‘name’, ‘email’, ‘password’, ‘active’, ‘last_login_ip’, ‘current_login_ip’, ‘login_count’)
dateformat = ‘%F %T %z’
flask_diamond.models.user.roles_users = Table(‘roles_users’, MetaData(bind=None), Column(‘user_id’, Integer(),
A secondary table is used for the one-to-many relationship: User has many Roles
models.role
class flask_diamond.models.role.Role(**kwargs)
Bases:
flask_sqlalchemy.Model,
flask_security.core.RoleMixin,
flask_diamond.mixins.crud.CRUDMixin, flask_diamond.mixins.marshmallow.MarshmallowMixin
For the purpose of access controls, Roles can be used to create collections of users and give them permissions
as a group.
classmethod add_default_roles()
Create a basic set of users and roles
Returns None
description
string – a sentence describing the role
id
integer – primary key
name
string – what the role is called
class flask_diamond.models.role.RoleSchema(obj=None,
extra=None,
only=None,
exclude=None,
prefix=u’‘,
strict=False,
many=False,
skip_missing=False,
context=None)
Bases: flask_marshmallow.Schema
class Meta
additional = (‘id’, ‘name’, ‘description’)
7.1.3 mixins
mixins.crud
class flask_diamond.mixins.crud.CRUDMixin
Convenience functions for CRUD operations.
Adapted from flask-kit.
7.1. API
65
Flask-Diamond Documentation, Release 0.4.0
classmethod create(_commit=True, **kwargs)
Create a new object.
Parameters
• commit (boolean) – whether to commit the change immediately to the database
• kwargs (dict) – parameters corresponding to the new values
Returns the object that was created
delete(_commit=True)
Delete this object.
Parameters commit (boolean) – whether to commit the change immediately to the database
Returns whether the delete was successful
classmethod find(**kwargs)
Find an object in the database with certain properties.
Parameters kwargs (dict) – the values of the object to find
Returns the object that was found, or else None
classmethod find_or_create(_commit=True, **kwargs)
Find an object or, if it does not exist, create it.
Parameters kwargs (dict) – the values of the object to find or create
Returns the object that was created
classmethod get_by_id(id)
Retrieve an object of this class from the database.
Parameters id (integer) – the id of the object to be retrieved
Returns the object that was retrieved
save(_commit=True)
Save this object to the database.
Parameters commit (boolean) – whether to commit the change immediately to the database
Returns the object that was saved
update(_commit=True, **kwargs)
Update this object with new values.
Parameters
• commit (boolean) – whether to commit the change immediately to the database
• kwargs (dict) – parameters corresponding to the new values
Returns the object that was updated
mixins.marshmallow
class flask_diamond.mixins.marshmallow.MarshmallowMixin
dump()
serialize the Model object as a python object
66
Chapter 7. API Reference
Flask-Diamond Documentation, Release 0.4.0
classmethod dump_all()
write all objects of Model class to an array of python objects
dumpf(file_handle)
write a Model object to file_handle as a JSON string
classmethod dumpf_all(file_handle)
write all objects of Model class to file_handle as JSON
dumps()
serialize the Model object as a JSON string
classmethod dumps_all()
write all objects of Model class to a JSON-encoded array
classmethod load(python_obj)
create a Model object from a python object
classmethod load_all(python_objects)
create objects of Model class from an array of python objects
classmethod loadf(file_handle)
create a Model object from a file_handle pointing to a JSON file
classmethod loadf_all(file_handle)
create objects of Model class from a file containing an array of JSON-encoded objects
classmethod loads(buf )
create a Model object from a JSON-encoded string
classmethod loads_all(buf )
create objects of Model class from a string containing an array of JSON-encoded objects
7.1.4 facets
facets.accounts
flask_diamond.facets.accounts.init_accounts(self, user=None, role=None)
Initialize Security for application.
Parameters kwargs (dict) – parameters that will be passed through to Flask-Security
Returns None
A number of common User account operations are provided by Flask- Security. This function is responsible for
associating User models in the database with the Security object.
In case you need to override a Flask-Security form (as is the case with implementing CAPTCHA) then you must
use super() from within your application and provide any arguments destined for Flask-Security.
>>> def ext_security(self):
>>>
super(MyApp, self).ext_security(confirm_register_form=CaptchaRegisterForm)
facets.administration
flask_diamond.facets.administration.init_administration(self,
index_view=None,
user=None, role=None)
Initialize the Administrative GUI.
7.1. API
67
Flask-Diamond Documentation, Release 0.4.0
Parameters index_view (AdminIndexView) – the View that will act as the index page of the admin
GUI.
Returns None
The administration GUI is substantially derived from Flask-Admin. When this function is called, it will instantiate blueprints so the application serves the admin GUI via the URL http://localhost/admin.
Typically, you will want to call this function even if you override it. The following example illustrates using
super() to invoke this administration() function from within your own application.
>>> admin = super(MyApp, self).administration(
>>>
index_view=MyApp.modelviews.RedirectView(name="Home")
>>> )
facets.blueprints
flask_diamond.facets.blueprints.init_blueprints(self )
Initialize blueprints.
Returns None
By default, this function does nothing. Your application needs to overload this function in order to implement
your View functionality. More information about blueprints can be found in the Flask documentation.
facets.configuration
flask_diamond.facets.configuration.init_configuration(self )
Load the application configuration from the SETTINGS environment variable.
Returns None
SETTINGS must contain a filename that points to the configuration file.
facets.database
flask_diamond.facets.database.init_database(self )
Initialize database
Returns None
Flask-Diamond assumes you are modelling your solution using an Entity- Relationship framework, and that
the application will use a relational database (e.g. MySQL, Postgres, or SQlite3) for model persistence. Thus,
SQLAlchemy and Flask- SQLalchemy are used for database operations.
Typically, this just works as long as SQLALCHEMY_DATABASE_URI is set correctly in the application configuration.
facets.debugger
flask_diamond.facets.debugger.init_debugger(self )
Initialize the DebugToolbar
Returns None
68
Chapter 7. API Reference
Flask-Diamond Documentation, Release 0.4.0
The DebugToolbar is a handy utility for debugging your application during development.
This function obeys the DEBUG_TOOLBAR configuration setting. Only if this value is explicitly set to True will
the Debug Toolbarr run.
facets.email
flask_diamond.facets.email.init_email(self )
Initialize email facilities.
Returns None
Flask-Mail is a useful tool for creating and sending emails from within a Flask application. There are a number
of configuration settings beginning with MAIL_ that permit control over the SMTP credentials used to send
email.
facets.forms
flask_diamond.facets.forms.add_helpers(app)
Create any Jinja2 helpers needed.
flask_diamond.facets.forms.init_forms(self )
WTForms helpers
Returns None
WTForms is a great library for using forms and Flask-WTF provides good integration with it. WTForms helpers
enable you to add custom filters and other custom behaviours.
facets.handlers
flask_diamond.facets.handlers.init_error_handlers(self )
Initialize handlers for HTTP error events
Returns None
Flask is able to respond to HTTP error codes with custom behaviours. By default, it will redirect error 403
(forbidden) to the login page.
flask_diamond.facets.handlers.init_request_handlers(self )
request handlers
Returns None
Flask handles requests for URLs by scanning the URL path. Typically, any serious functionality will be collected
into Views. However, this function is a chance to define a few simple utility URLs.
If in your application you want to disable the default handlers in Flask-Diamond, you can override them like
this.
>>> def request_handlers(self):
>>>
pass
facets.logs
flask_diamond.facets.logs.init_logs(self )
Initialize a log file to collect messages.
7.1. API
69
Flask-Diamond Documentation, Release 0.4.0
Returns None
This file may be written to using
>>> flask.current_app.logger.info("message")
facets.marshalling
flask_diamond.facets.marshalling.init_marshalling(self )
Initialize Marshmallow.
Returns None
facets.rest
flask_diamond.facets.rest.init_rest(self, api_map=None)
Initialize REST API.
Returns None
By default, this function does nothing. Your application needs to overload this function in order to implement
your REST API. More information about REST can be found in the documentation.
api_map is an optional function that can be responsible for setting up the API. This is usually accomplished
with a series of add_resource() invocations. api_map must take one parameter, which is the Flask-Restful object
managed by Flask-Diamond.
You will end up writing something like this in your application:
def api_map(rest): rest_api.add_resource(Blah)
facets.signals
flask_diamond.facets.signals.init_signals(self )
Initialize Flask signal handlers
Returns None
Flask provides a number of signals corresponding to things that happen during the operation of the application,
which can also be thought of as events. It is possible to create signal handlers that will respond to these events
with some behaviour.
facets.task_queue
flask_diamond.facets.task_queue.init_task_queue(self )
Initialize celery.
facets.webassets
flask_diamond.facets.webassets.init_webassets(self )
Initialize web assets.
Returns None
webassets make it simpler to process and bundle CSS and Javascript assets. This can be baked into a Flask
application using Flask-Assets
70
Chapter 7. API Reference
Python Module Index
f
flask_diamond, 63
flask_diamond.facets, 67
flask_diamond.facets.accounts, 67
flask_diamond.facets.administration, 67
flask_diamond.facets.blueprints, 68
flask_diamond.facets.configuration, 68
flask_diamond.facets.database, 68
flask_diamond.facets.debugger, 68
flask_diamond.facets.email, 69
flask_diamond.facets.forms, 69
flask_diamond.facets.handlers, 69
flask_diamond.facets.logs, 69
flask_diamond.facets.marshalling, 70
flask_diamond.facets.rest, 70
flask_diamond.facets.signals, 70
flask_diamond.facets.task_queue, 70
flask_diamond.facets.webassets, 70
flask_diamond.mixins.crud, 65
flask_diamond.mixins.marshmallow, 66
flask_diamond.models.role, 65
flask_diamond.models.user, 63
71
Flask-Diamond Documentation, Release 0.4.0
72
Python Module Index
Index
A
active (flask_diamond.models.user.User attribute), 63
add_admin_user() (flask_diamond.models.user.User class
method), 64
add_default_roles()
(flask_diamond.models.role.Role
class method), 65
add_guest_user() (flask_diamond.models.user.User class
method), 64
add_helpers() (in module flask_diamond.facets.forms),
69
add_role() (flask_diamond.models.user.User method), 64
additional (flask_diamond.models.role.RoleSchema.Meta
attribute), 65
additional (flask_diamond.models.user.UserSchema.Meta
attribute), 65
dump_all() (flask_diamond.mixins.marshmallow.MarshmallowMixin
class method), 66
dumpf() (flask_diamond.mixins.marshmallow.MarshmallowMixin
method), 67
dumpf_all() (flask_diamond.mixins.marshmallow.MarshmallowMixin
class method), 67
dumps() (flask_diamond.mixins.marshmallow.MarshmallowMixin
method), 67
dumps_all() (flask_diamond.mixins.marshmallow.MarshmallowMixin
class method), 67
E
email (flask_diamond.models.user.User attribute), 64
F
facet() (flask_diamond.Diamond method), 63
find() (flask_diamond.mixins.crud.CRUDMixin class
method), 66
confirm() (flask_diamond.models.user.User method), 64
find_or_create()
(flask_diamond.mixins.crud.CRUDMixin
confirmed_at (flask_diamond.models.user.User attribute),
class
method),
66
64
flask_diamond
(module),
63
create() (flask_diamond.mixins.crud.CRUDMixin class
flask_diamond.facets
(module),
67
method), 65
flask_diamond.facets.accounts
(module),
67
create_app() (in module flask_diamond), 63
flask_diamond.facets.administration
(module),
67
CRUDMixin (class in flask_diamond.mixins.crud), 65
flask_diamond.facets.blueprints
(module),
68
current_login_at
(flask_diamond.models.user.User
flask_diamond.facets.configuration (module), 68
attribute), 64
current_login_ip
(flask_diamond.models.user.User flask_diamond.facets.database (module), 68
flask_diamond.facets.debugger (module), 68
attribute), 64
flask_diamond.facets.email (module), 69
flask_diamond.facets.forms (module), 69
D
flask_diamond.facets.handlers (module), 69
dateformat (flask_diamond.models.user.UserSchema.Meta
flask_diamond.facets.logs (module), 69
attribute), 65
flask_diamond.facets.marshalling (module), 70
delete()
(flask_diamond.mixins.crud.CRUDMixin
flask_diamond.facets.rest (module), 70
method), 66
flask_diamond.facets.signals (module), 70
description (flask_diamond.models.role.Role attribute),
flask_diamond.facets.task_queue (module), 70
65
flask_diamond.facets.webassets (module), 70
Diamond (class in flask_diamond), 63
flask_diamond.mixins.crud (module), 65
dump() (flask_diamond.mixins.marshmallow.MarshmallowMixin
flask_diamond.mixins.marshmallow (module), 66
method), 66
flask_diamond.models.role (module), 65
flask_diamond.models.user (module), 63
C
73
Flask-Diamond Documentation, Release 0.4.0
G
loads_all() (flask_diamond.mixins.marshmallow.MarshmallowMixin
class method), 67
get_by_id()
(flask_diamond.mixins.crud.CRUDMixin
login_count
(flask_diamond.models.user.User attribute),
class method), 66
64
I
id (flask_diamond.models.role.Role attribute), 65
id (flask_diamond.models.user.User attribute), 64
init_accounts() (flask_diamond.Diamond method), 63
init_accounts()
(in
module
flask_diamond.facets.accounts), 67
init_administration() (flask_diamond.Diamond method),
63
init_administration()
(in
module
flask_diamond.facets.administration), 67
init_blueprints()
(in
module
flask_diamond.facets.blueprints), 68
init_configuration()
(in
module
flask_diamond.facets.configuration), 68
init_database()
(in
module
flask_diamond.facets.database), 68
init_debugger()
(in
module
flask_diamond.facets.debugger), 68
init_email() (in module flask_diamond.facets.email), 69
init_error_handlers()
(in
module
flask_diamond.facets.handlers), 69
init_forms() (in module flask_diamond.facets.forms), 69
init_logs() (in module flask_diamond.facets.logs), 69
init_marshalling()
(in
module
flask_diamond.facets.marshalling), 70
init_request_handlers()
(in
module
flask_diamond.facets.handlers), 69
init_rest() (in module flask_diamond.facets.rest), 70
init_signals() (in module flask_diamond.facets.signals),
70
init_task_queue()
(in
module
flask_diamond.facets.task_queue), 70
init_webassets()
(in
module
flask_diamond.facets.webassets), 70
M
MarshmallowMixin
(class
flask_diamond.mixins.marshmallow), 66
in
N
name (flask_diamond.models.role.Role attribute), 65
name (flask_diamond.models.user.User attribute), 64
P
password (flask_diamond.models.user.User attribute), 64
R
register()
(flask_diamond.models.user.User
class
method), 64
rm_system_users()
(flask_diamond.models.user.User
class method), 64
Role (class in flask_diamond.models.role), 65
roles (flask_diamond.models.user.User attribute), 64
roles_users (in module flask_diamond.models.user), 65
RoleSchema (class in flask_diamond.models.role), 65
RoleSchema.Meta (class in flask_diamond.models.role),
65
S
save()
(flask_diamond.mixins.crud.CRUDMixin
method), 66
super() (flask_diamond.Diamond method), 63
T
teardown() (flask_diamond.Diamond method), 63
U
update()
(flask_diamond.mixins.crud.CRUDMixin
method), 66
last_login_at (flask_diamond.models.user.User attribute), User (class in flask_diamond.models.user), 63
UserSchema (class in flask_diamond.models.user), 65
64
last_login_ip (flask_diamond.models.user.User attribute), UserSchema.Meta (class in flask_diamond.models.user),
65
64
load() (flask_diamond.mixins.marshmallow.MarshmallowMixin
class method), 67
load_all() (flask_diamond.mixins.marshmallow.MarshmallowMixin
class method), 67
loadf() (flask_diamond.mixins.marshmallow.MarshmallowMixin
class method), 67
loadf_all() (flask_diamond.mixins.marshmallow.MarshmallowMixin
class method), 67
loads() (flask_diamond.mixins.marshmallow.MarshmallowMixin
class method), 67
L
74
Index
Was this manual useful for you? yes no
Thank you for your participation!

* Your assessment is very important for improving the work of artificial intelligence, which forms the content of this project

Download PDF

advertisement