3.3. Tutorial: ORMs in Flask#
In this tutorial we will work step-by-step to build a web app using Flask and SQLAlchemy ORM to keep track of a list of books in your personal collection.
At the end of the tutorial you will have built a web app that:
lists all books in your collection
supports adding new books
does not require any SQL!
3.3.1. Setup#
To begin, we will make a basic Flask web app that shows a list of books in the database, which at start will be empty.
We will use the flask-sqlalchemy extension, which simplifies the integration of SQLAlchemy’s ORM with Flask.
my-books
│
├── app.py
├── static
└── templates
└── index.html
Flask app#
The code below is our Flask app definition.
1from flask import Flask, render_template
2from flask_sqlalchemy import SQLAlchemy
3
4app = Flask(__name__)
5
6app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///books.db'
7db = SQLAlchemy(app)
8
9# Define the Book model
10class Book(db.Model):
11 id = db.Column(db.Integer, primary_key=True)
12 title = db.Column(db.String(150), nullable=False)
13 author = db.Column(db.String(100), nullable=False)
14 publication_date = db.Column(db.String(10)) # Simplified for demo
15 genre = db.Column(db.String(50))
16
17
18# Create the database if it doesn't exist
19with app.app_context():
20 db.create_all()
21
22@app.route('/')
23def home():
24 # Query all books (empty for now)
25 books = Book.query.all()
26 return render_template('index.html', books=books)
27
28if __name__ == '__main__':
29 app.run(debug=True, reloader_type='stat', port=5000)
Explanation:
Because we are using
flask-sqlalchemy
, our database configuration and Model specification is differentNote that most SQLAlchemy functions and classes are available through the
db
objectA nice feature of
flask-sqlalchemy
is that common database operations are also available as methods of the model class e.g.Book.query.all()
, instead of through asession
object.
Homepage template#
The template for the homepage is relatively simple. It will show a list of books if available, otherwise it shows that no books are found.
1<!-- templates/home.html -->
2<!DOCTYPE html>
3<html lang="en">
4<head>
5 <meta charset="UTF-8">
6 <title>Book List</title>
7</head>
8<body>
9 <h1>My Book Collection</h1>
10 <ul>
11 {% for book in books %}
12 <li>{{ book.title }} by {{ book.author }}</li>
13 {% else %}
14 <li>No books found yet!</li>
15 {% endfor %}
16 </ul>
17</body>
18</html>
3.3.2. Adding Books#
To add books we need to:
Add a form to our homepage to collect the book information and submit a POST request to the web app
Add a new route to our Flask app that accepts POST requests and converts form data to a model object
Homepage template#
The template for the homepage should now include a form for adding books, like the one shown below.
1<!-- templates/home.html -->
2<!DOCTYPE html>
3<html lang="en">
4<head>
5 <meta charset="UTF-8">
6 <title>Book List</title>
7</head>
8<body>
9 <h1>My Book Collection</h1>
10
11 <h2>Add a New Book</h2>
12 <form action="/add" method="post">
13 <label for="title">Title:</label>
14 <input type="text" id="title" name="title" required><br>
15
16 <label for="author">Author:</label>
17 <input type="text" id="author" name="author" required><br>
18
19 <label for="publication_date">Publication Date:</label>
20 <input type="text" id="publication_date" name="publication_date"><br>
21
22 <label for="genre">Genre:</label>
23 <input type="text" id="genre" name="genre"><br>
24
25 <input type="submit" value="Add Book">
26 </form>
27
28 <ul>
29 {% for book in books %}
30 <li>{{ book.title }} by {{ book.author }}</li>
31 {% else %}
32 <li>No books found yet!</li>
33 {% endfor %}
34 </ul>
35</body>
36</html>
Flask app#
Now we need a corresponding route in our Flask app to accept the form data.
Below is the route function that we need to add.
28@app.route('/add', methods=['POST'])
29def add_book():
30 title = request.form.get('title')
31 author = request.form.get('author')
32 publication_date = request.form.get('publication_date')
33 genre = request.form.get('genre')
34
35 new_book = Book(
36 title=title,
37 author=author,
38 publication_date=publication_date,
39 genre=genre
40 )
41 db.session.add(new_book)
42 db.session.commit()
43
44 return redirect(url_for('home'))
Explanation:
Inside the route
/add
the form data is collectedThis data is used to create a new
Book
instanceUsing the
db.session
object it is added and committed to the databaseThe user is redirected to the homepage, where the new book will appear on the list