Skip to content

Creating and modifying pages

Creating a new page

To create a new page, we first create a session and retrieve a root page, which will then hold our new page:

import ultimate_notion as uno

ROOT_PAGE = 'Tests'  # page with connected Ultimate Notion integration
notion = uno.Session.get_or_create()

root_page = notion.search_page(ROOT_PAGE).item()

Using root_page we can simply create a new page with:

my_page = notion.create_page(parent=root_page, title='Autogenerated page')

Our new page is empty and we can check that with:

assert my_page.children == []

Adding content to a page

Our new page can now be populated with the typical Notion blocks from the blocks module. Let's create a heading 1 block and append it to our page with:

h1 = uno.Heading1('My new page')
my_page.append(h1)

We can also append several blocks at once:

my_page.append([
    uno.Paragraph('Some text...'),
    uno.Code(
        'SELECT * FROM MY_TABLE',
        language=uno.CodeLang.SQL,
        caption='SQL Query'
        ),
    uno.Quote(
        '"You know, for a mathematician, he did not have enough imagination. '
        'But he has become a poet and now he is fine." - D. Hilbert',
        color=uno.Color.BLUE
        ),
    uno.Callout('Ultimate Notion rocks!', color=uno.BGColor.PURPLE, icon='🚀'),
    uno.Heading2('Showing off some more...'),
    uno.BulletedItem('First bulleted item'),
    uno.BulletedItem('Second bulleted item'),
    uno.NumberedItem('First numbered item', color=uno.Color.RED),
    uno.NumberedItem('Second numbered item', color=uno.Color.RED),
    uno.ToDoItem('First checked Todo', checked=True),
    uno.ToDoItem('Second open Todo'),
    uno.ToggleItem('Toggle item'),
    uno.Divider(),
    uno.Heading3('Some more fancy stuff...'),
    uno.TableOfContents(color=uno.Color.PINK),
    uno.Breadcrumb(),
    uno.Embed('https://www.youtube.com/watch?v=dQw4w9WgXcQ', caption='Rick'),
    uno.Bookmark('https://www.youtube.com/watch?v=dQw4w9WgXcQ'),
    uno.Equation(r'-1 = \exp(i \pi)'),
    ]
)

Let's say we have forgotten one block and want to add it at a specific position, i.e. after another block:

new_paragraph = uno.Paragraph('Some more text, which was added afterwards...')
my_page.append(new_paragraph, after=my_page.children[2])

As the block reference new_paragraph is automatically updated when appended to the page, we can also use it now as a reference to append a new block after it, e.g.:

to_be_deleted_paragraph = uno.Paragraph('Block to be deleted')
my_page.append(to_be_deleted_paragraph, after=new_paragraph)

To delete a block from a page, we can just call .delete() on it:

to_be_deleted_paragraph.delete()

This is how our page now looks like this:

Block page

Note

For type hinting, use AnyBlock for a general block, e.g.

page_children: uno.AnyBlock = my_page.children

Nested blocks

A really useful feature of Notion blocks is that most of them can be nested Therefore some blocks, like paragaphs, quotes, toggable headings and so on, can have children and thus also have an append method, just like a page.

Let's create a new page where we store various file types under a toggable Headning:

file_page = notion.create_page(parent=root_page, title='Page with nested blocks')

heading = uno.Heading1('My files', toggleable=True)
file_page.append(heading)

heading.append([
    uno.File(
        'robots.txt',
        'https://www.google.de/robots.txt',
        caption='Google Robots'
        ),
    uno.Image(
        'https://cdn.pixabay.com/photo/2019/08/06/09/16/flowers-4387827_1280.jpg',
        caption='Path on meadow'
        ),
    uno.Video(
        'https://www.youtube.com/watch?v=dQw4w9WgXcQ',
        caption='Rick Roll'
        ),
    uno.PDF(
        'https://www.iktz-hd.de/fileadmin/user_upload/dummy.pdf',
        caption='Dummy PDF'
        ),
])

Info

We can only add children blocks to a block that is already in notion, i.e. was already appended to a page. You can also programmatically check that with the in_notion property of a block.

Columns & tables

Assume that we want to structure our page a bit more using columns. We define a set of columns using the Columns block. This block now behaves like a list of where each element presents a column. We can now just append to a column, e.g.:

page = notion.create_page(parent=root_page, title='Page with advanced blocks')

cols = uno.Columns(2)
page.append(cols)

cols[0].append(uno.Paragraph('Column 1'))
cols[1].append(uno.Paragraph('Column 2'))

Using the some concept, we can also create a table but this time we specify the cells instead of columns. Creating a 4x6 table with 4 rows and 6 columns where the first row is a header for the columns, thus we set column_header to true, which might be a bit counter-intuitive at first:

table = uno.Table(4, 6, row_header=False, column_header=True)

page.append(table)

Failure

We now have an empty table but filling wit with content is currently not implemented 🙈.

To access the rows and cells we can call:

rows = table.rows
cells_of_first_row = rows[0].cells

Advanced blocks

There are some additional more advanced blocks like link to a page and synced block. Let's take a look at those.

Assume we have our "Getting Started"-page and want to link to it from the page, we just created above.

target_page = notion.search_page('Getting Started').item()

page.append(uno.LinkToPage(target_page))

A synced block is a different kind of beast. We first have to define an original block, which acts as a container for other blocks that should be synced. Then we append various blocks to it and finally create a synced block, which will be synchronized with the content of the original block.

orig_block = uno.SyncedBlock(uno.Paragraph('This is a synced paragraph'))
page.append(orig_block)

sync_block = orig_block.create_synced()
page.append(sync_block)

Now we have two paragraphs, with the second always reflecting the content of the first.

Working with texts

So far we passed to most blocks basic strings and only provided in some cases a colour for the whole block. Notion allows much fancier formatting for text but also inline formulas and mentions of various types. This is supported by the four types Text, Math, Mention and RichText. The first three types are the primary building blocks and when composed result in a RichText. An example illustrates this:

page = notion.create_page(parent=root_page, title='Page with fancy text')

rt = uno.Text('This is a ') + uno.Text('bold', bold=True) + uno.Text(' word.\n')
assert isinstance(rt, uno.RichText)

rt += 'We can even add a normal string to it.\n'
rt += uno.Text('Now some ') + uno.Text('inline formula: ', color=uno.Color.RED)
rt += uno.Math(r'-1 = e^{i \pi}') + '\n'
rt += uno.join([
    uno.Text('All', italic=True),
    uno.Text('possible', underline=True),
    uno.Text('formatting, ', color=uno.BGColor.PURPLE),
    uno.Text('is', code=True),
    uno.Text('it?', strikethrough=True),
    uno.Text('it not?', italic=True, bold=True)
    ])

page.append(uno.Paragraph(rt))

To achieve fancy formatting, we have to mix and match Text elements to compose the formatting we want. For longer texts without content, uno.RichText should be directly used as there is a length limitation on `Text.

Warning

Be cautious with the operator precedence of += and + in the example above. While rt += 'We can even add a normal string to it.\n' works just as rt is already of type RichText, rt += 'We can even add a normal string to ' + uno.Text('it.'n')' would not work as we would first conatenate a str with a Text before we append it to a RichText.

Let's see how we can mention a person, page, database or even a date.

from datetime import datetime

person = notion.search_user('Florian Wilhelm').item()
dummy_db = notion.create_db(parent=root_page)
intro_page = notion.search_page('Getting Started').item()
my_date = datetime(1592, 3, 14) # or better use the pendulum library

rt = uno.join([
    uno.Mention(person),
    uno.Mention(dummy_db),
    uno.Mention(intro_page),
    uno.Mention(my_date)
    ], delim=' : ')
page.append(uno.Paragraph(rt))

Let's take a look how our fancy text page looks like in the end.

Fancy text page

Note

For type hinting, use AnyText for a general text element, which is either Text, Math, Mention and RichText, e.g.

text: uno.AnyText = uno.Text('Some text...')