Introduction
In this tutorial we are going to build an application with flask. We will setup management commands, a sqlalchemy model and an API rest to access and modify the model.
Step 1: Prepare virtualenv and install requirements
We are going to use pyenv + virutalenv plugin. For python package scaffolding we will use cookie cutter. If you want to know how to setup pyenv, please pyenv+virtualenv tutorial. In particular we will use Python 3.
pyenv virtualenv 3.6.0 flask_app
pyenv activate flask_app
pip install cookiecutter
# now create with cookiecutter a python package
cookiecutter https://github.com/audreyr/cookiecutter-pypackage.git
CD into the new directory and open the file requirements_dev.txt and paste the following:
bumpversion==0.5.3
wheel==0.29.0
watchdog==0.8.3
flake8==2.6.0
tox==2.3.1
coverage==4.1
Sphinx==1.4.8
cryptography==1.7
PyYAML==3.11
Flask==0.12.1
Flask-Migrate==2.0.3
Flask-RESTful==0.3.5
Flask-Script==2.0.5
Flask-SQLAlchemy==2.2
In this tutorial we are going to use Flask-SQLAlchemy, Flask-Migrate, Flask-RESTful and Flask-Script.
- Flask-Script: Provides support for writing external scripts.
- Flask-SQLAlchemy: Provides support for using sqlalchemy.
- Flask-Migrate: Allows to add migration to the sqlalchemy model.
- Flask-RESTful: Add support to quickly build REST APIs.
Step 2: Creating flask skeleton directories and show a Hello World message
We are going to start with two new directories: static and templates.
In the directory where you setup.py was created, execute the follwoing commands:
mkdir -p flask_app/{templates,static,views,scripts}
touch flask_app/scripts/__innit__.py
touch flask_app/scripts/app.py
touch flask_app/scripts/start.py
touch flask_app/scripts/manage.py
touch flask_app/views/__init__.py
touch flask_app/__init__.py
touch flask_app/models.py
touch flask_app/settings.py
On the flask_app/app.py we are going to add the code for app initialization. We will import the views, so flask can add those views.
from flask import Flask
from flask_restful import Api
from flask_app.settings import SQLALCHEMY_DATABASE_URI, SQLALCHEMY_TRACK_MODIFICATIONS
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = SQLALCHEMY_DATABASE_URI
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = SQLALCHEMY_TRACK_MODIFICATIONS
db = SQLAlchemy(app)
api = Api(app)
# we need to import the views and model (which are not used here)
from flask_app import views
from flask_app.models import Animal
Next we will add the index route and show a "Hello, World!" messaga. Add the following content to the views/init.py file:
from flask_app import app
@app.route('/')
@app.route('/index')
def index():
return "Hello, World!"
Add the following code to the flask_app/scripts/start.py. This code will start the flask application in debug mode
from flask_script import Manager
from flask_app.app import app
manager = Manager(app)
if __name__ == "__main__":
manager.run()
Now test your application running the file:
python setup.py develop # else your imports will fail
python scripts/start.py runserver
# open you browser at http://localhost:5000/
# you should see the "Hello, World!" string.
Step 3: Adding the model
In this simple tutorial we are going to show animals and colors form a model. We are not going to add authentication to make this tutorial simple. Here is the model we are going to show and create records. Open the file flask_app/models.py and add the following content:
from flask_app.app import db
class Animal(db.Model):
__tablename__ = 'animal'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(100))
color = db.Column(db.String(100))
Open the settings.py and add the following:
SQLALCHEMY_DATABASE_URI = 'sqlite:///flask_app.db'
SQLALCHEMY_TRACK_MODIFICATIONS = False
Change the settings as you need, in this example we will use sqlite. For more information on how to setup the url see sqlalchemy engince docs.
Now we are going to create a manage script for the migrations. Open the file flask_app/scripts/manage.py to append these content:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_script import Manager
from flask_migrate import Migrate, MigrateCommand
from flask_app.app import app, db
migrate = Migrate(app, db)
manager = Manager(app)
manager.add_command('migrate', MigrateCommand)
if __name__ == '__main__':
manager.run()
Now initialize the empty database schema using:
python flask_app/scraipts/manage.py migrate init
# the next command will create the sqlite3 file with the database
python flask_app/scraipts/manage.py migrate migrate
# to apply the migration to the database
python flask_app/scraipts/manage.py migrate upgrade
This will create a directory called migrations. You need to save this directory in your git in order to have historical model schema changes. At this point we have enable migrations for our model.
Step 4: Adding a REST API
To access the model we just created we are going to use Flask-RESTful.
Open the file views/init.py
from flask import Flask, request
from flask_restful import reqparse, Resource, Api
from nichescore.app import api, db
from nichescore.models import Animal
class AnimalsResource(Resource):
def get(self, animal_id):
animal = db.session.query(Animal).filter_by(id=animal_id).first()
if not animal:
return {'message': 'Not found'}, 404
return {animal_id: animal}
def put(self, animal_id):
animal = db.query(Animal).filter_by(id=animal_id)
animal.color = request.form['color']
db.session.commit()
return {animal_id: animal}
class AnimalsListResource(Resource):
def get(self):
return [{animal.id: {'name': animal.name, 'color': animal.color}} for animal in db.session.query(Animal).all()]
def post(self):
parser = reqparse.RequestParser()
parser.add_argument('name')
parser.add_argument('color')
args = parser.parse_args()
if not 'name' in args or not 'color' in args:
# we return bad request since we require name and color
return {'message': 'Missing required parameters.'}, 400
new_animal = Animal(name=args['name'], color=args['color'])
db.session.add(new_animal)
db.session.commit()
return {new_animal.id: {'name': animal.name, 'color': animal.color}}, 201
api.add_resource(AnimalsResource, 'animal/<animal_id>')
api.add_resource(AnimalsListResource, 'animals')
Now for testing the API we first are going to create a new animal using curl:
curl http://localhost:5000/animals -d "name=test;color=red" -X POST -v
You can get the list with:
curl http://localhost:5000/animals -v
Get one animal by id:
curl http://localhost:5000/animal/1 -v
Edit an animal by id:
curl http://localhost:5000/animal/1 -d "color=green" -X PUT