In depth: Store model
Code for models/store.py
from db import db
class StoreModel(db.Model):
__tablename__ = "stores"
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(80))
items = db.relationship("ItemModel", lazy="dynamic")
def __init__(self, name):
self.name = name
def json(self):
return {
"id": self.id,
"name": self.name,
"items": [item.json() for item in self.items.all()],
}
@classmethod
def find_by_name(cls, name):
return cls.query.filter_by(name=name).first()
@classmethod
def find_all(cls):
return cls.query.all()
def save_to_db(self):
db.session.add(self)
db.session.commit()
def delete_from_db(self):
db.session.delete(self)
db.session.commit()
SQLAlchemy relationships
This model is very similar to the ItemModel
, but we see a new concept near the column definitions:
items = db.relationship("ItemModel", lazy="dynamic")
SQLAlchemy is smart enough to be able to construct a many-to-one relationship from this. Every item has a store_id
property, so the items
property of the StoreModel
becomes a list of those items.
Or at least, it would if we remove lazy="dynamic"
.
With lazy="dynamic"
, items
becomes a SQLAlchemy query, so whenever we want to access the items in the store we have to do something like this:
store = StoreModel.find_by_name("Amazon")
print(store.items.all())
That .all()
is the key part here, and only needed when lazy="dynamic"
. Since store.items
is a SQLAlchemy query, .all()
makes it go into the database and retrieve all the items. We call this a "lazy" property because the items are not loaded until we do .all()
.
If we take away lazy="dynamic"
, then the items are loaded from the database as soon as the StoreModel
object is created.
This can be quite powerful, because if we add a new item after the StoreModel
object has been created, we can still see that the item is related to the store when we load from the database. Let's look at an example:
Adding an item to a store
Whenever an item is created and saved to the database with the correct store_id
, SQLAlchemy can relate it back to the store. For example:
store = StoreModel("Amazon")
store.save_to_db() # This gives our store an 'id' since it's generated by the database
item = ItemModel("Chair", 12.99, 1)
item.save_to_db()
print(store.items.all()) # Will give us that Chair
Example: without lazy="dynamic"
Imagine we removed lazy="dynamic"
from the db.relationship
definition.
The code above would change to this (remove .all()
):
store = StoreModel("Amazon")
store.save_to_db() # This gives our store an 'id' since it's generated by the database
item = ItemModel("Chair", 12.99, 1)
item.save_to_db()
print(store.items) # Will give us an empty list
And the code would no longer give us the new item, since it was created after the StoreModel
object was created.