Data models & schemas¶
We gonna create two simple databases with a relation quite similar as described in the Notion docs. We gonna have a database for customers and one for items, which customers can purchase.
Let's first initialize a Notion session with
import ultimate_notion as uno
notion = uno.Session.get_or_create()
Declarative schemas & relations¶
We start by defining the schema for our items in a really pythonic way. The schema should have three columns, the title column Name
for the name of an item, e.g. "Jeans", a size column Size
and of course a Price
column numbers in Dollars. The size of of piece of clothing can be chosen from the options S
, M
and L
. We can directly translate this schema into Python code:
class Size(uno.OptionNS):
"""Namespace for the select options of our various sizes"""
S = uno.Option(name='S', color='green')
M = uno.Option(name='M', color='yellow')
L = uno.Option(name='L', color='red')
class Item(uno.PageSchema, db_title='Item DB'):
"""Database of all the items we sell"""
name = uno.Column('Name', uno.ColType.Title())
size = uno.Column('Size', uno.ColType.Select(Size))
price = uno.Column('Price', uno.ColType.Number(uno.NumberFormat.DOLLAR))
Since a database needs to be a block wighin a page, we assume there is a page called Tests
, which is connected with this integration. We retrieve the object of this page and create the database with the page as parent page.
root_page = notion.search_page('Tests', exact=True).item()
item_db = notion.create_db(parent=root_page, schema=Item)
Now we create a database for our customers and define a one-way Relation to the items:
class Customer(uno.PageSchema, db_title='Customer DB'):
"""Database of all our beloved customers"""
name = uno.Column('Name', uno.ColType.Title())
purchases = uno.Column('Items Purchased', uno.ColType.Relation(Item))
customer_db = notion.create_db(parent=root_page, schema=Customer)
Warning
To create a database that has a relation to another database requires that the target database already exists. Thus the order of creating the databases from the schemas is important.
All available column database are provided by ColType, which is just a namespace for the various column types defined in schema. Column types with the class variable allowed_at_creation
set to False
are currently not supported by the Notion API. when creating a new database.
New database entries¶
Now that we have created those two databases, we can start filling them with a few entries either using the create_page method of the database object:
t_shirt = item_db.create_page(name='T-shirt', size=Size.L, price=17)
khaki_pants = item_db.create_page(name='Khaki pants', size=Size.M, price=25)
tank_top = item_db.create_page(name='Tank top', size=Size.S, price=15)
or we can also directly use the create method of the schema if the schema is already bound to a database:
lovelace = Customer.create(name='Ada Lovelace', purchases=[tank_top])
hertzfeld = Customer.create(name='Andy Herzfeld', purchases=[khaki_pants])
engelbart = Customer.create(
name='Doug Engelbart', purchases=[khaki_pants, t_shirt]
)
Info
The keyword-arguments are exactly the class variables from the page schemas Item
and Customer
above.
This is how are two databases item_db
and customer_db
look like in the Notion UI right now:
Note
The description of the databases corresponds to the the docstring of the schema classes Item
and Customer
.
Two-way & self relations¶
Notion also supports two-way relations and so does Ultimate Notion. Taking the same example as before, imagine that we also wanted to see direclty which customers bought a specific item. In this case the one-way relation Items Purchased
from Customer
needs to become a two-way relation. We can achieve this, with a simple modification in both schemas:
class Item(uno.PageSchema, db_title='Item DB'):
"""Database of all the items we sell"""
name = uno.Column('Name', uno.ColType.Title())
size = uno.Column('Size', uno.ColType.Select(Size))
price = uno.Column('Price', uno.ColType.Number(uno.NumberFormat.DOLLAR))
bought_by = uno.Column('Bought by', uno.ColType.Relation())
class Customer(uno.PageSchema, db_title='Customer DB'):
"""Database of all our beloved customers"""
name = uno.Column('Name', uno.ColType.Title())
purchases = uno.Column(
'Items Purchased',
uno.ColType.Relation(Item, two_way_col=Item.bought_by)
)
So what happens here is that we first create a target relation column bought_by
in Item
by not specifying any other schema. Then in Customer
, we define now a two-way column but specifying not only the schema Item
bouth also the column we want to synchronize with using the two_way_col
keyword.
Let's delete the old databases and recreate them with our updates schemas and a few items
item_db.delete(), customer_db.delete()
item_db = notion.create_db(parent=root_page, schema=Item)
customer_db = notion.create_db(parent=root_page, schema=Customer)
t_shirt = item_db.create_page(name='T-shirt', size=Size.L, price=17)
lovelace = Customer.create(name='Ada Lovelace', purchases=[t_shirt])
hertzfeld = Customer.create(name='Andy Herzfeld', purchases=[t_shirt])
and take a look at the two-way relation within item_db
:
Assume now that we want to have a schema that references itself, for instance a simple task list like where certain tasks can be subtasks of others:
class Task(uno.PageSchema, db_title='Task List'):
"""A really simple task lists with subtasks"""
task = uno.Column('Task', uno.ColType.Title())
due_by = uno.Column('Due by', uno.ColType.Date())
parent = uno.Column('Parent Task', uno.ColType.Relation(uno.SelfRef))
task_db = notion.create_db(parent=root_page, schema=Task)
from datetime import datetime, timedelta
today = datetime.now()
clean_house = Task.create(
task='Clean the house',
due_by=today + timedelta(weeks=4)
)
Task.create(
task='Vacuum living room',
due_by=today + timedelta(weeks=1),
parent=clean_house
)
Task.create(
task='Tidy up kitchen',
due_by=today + timedelta(days=3),
parent=clean_house
)
Warning
Due to a bug in the Notion API, it's not possible to have a two-way self-referencing relation right now. Creating a two-way relation leads to the creation of a one-way relation. We check for that and fail.