apistar-peewee

Peewee integration for Apistar


License
BSD-3-Clause
Install
pip install apistar-peewee==0.3.3

Documentation

Apistar Peewee ORM

Install

To use this you first need to install apistar_peewee and your chosen database driver:

$ pip install apistar_peewee
$ pip install psycopg2

For Sqlite you do not need any database driver.

Settings

You then need to add the database config to your settings:

from apistar.frameworks.wsgi import WSGIApp as App
import apistar_peewee


routes = [
   # ...
]

# Configure database settings.
settings = {
    'DATABASE': {
        'default': {
            'database': 'db1',
            'host': '127.0.0.1',
            'port': 5433,
            'user': 'user',
            'password': 'password',
            'engine': 'PooledPostgresqlDatabase'
        }
    }
}


app = App(
    routes=routes,
    settings=settings,
    commands=apistar_peewee.commands,  # Install custom commands.
    components=apistar_peewee.components  # Install custom components.
)

You can configure as many databases as you need:

settings = {
    'DATABASE': {
        'default': {
            'database': 'db1',
            'host': '127.0.0.1',
            'port': 5433,
            'user': 'user',
            'password': 'password',
            'engine': 'PooledPostgresqlDatabase'
        },
        'another_db': {
            'database': 'db2',
            'host': '127.0.0.1',
            'port': 5433,
            'user': 'user',
            'password': 'password',
            'engine': 'PooledPostgresqlDatabase'
        }
    }
}

Pass arguments to the database engine/driver:

settings = {
    'DATABASE': {
        'default': {
            'database': 'db1',
            'engine': 'PooledPostgresqlExtDatabase',
            'fields': {'varchar': 'varchar'},  # Extra arguments for database driver.
            'register_hstore': false
        }
    }
}

The apistar_peewee config above is similar to this Peewee config:

db = PooledPostgresqlExtDatabase("db1",
                                 fields={'varchar': 'varchar'},
                                 register_hstore=False)

Models

Create a new model:

from apistar_peewee import get_model_base
from peewee import *

Model = get_model_base()

class Customer(Model):
    name = CharField(max_length=255)

And for all other databases:

AnotherModel = get_model_base(alias='another_db')

class AnotherCustomer(AnotherModel):
    name = CharField(max_length=255)

Creating the database tables:

All models which name starts with _ or Abstract are abstract models. Such models are ignored by createtables and makemigrations commands.

Before starting your app you will likely need to create the database tables which you can do with the following command:

$ apistar createtables

Or use migrations.

For all commands you can specify database using --database argument. By default, it's default.

Migrations

Previous model state:

class Tweet(peewee.Model):
    f1 = peewee.CharField(max_length=50)
    price = peewee.IntegerField()
    price2 = peewee.IntegerField()

New model state:

class Tweet(peewee.Model):
    f1 = CharField(max_length=20)
    price = IntegerField()
    price2 = CharField(max_length=200)
    price3 = CharField(max_length=200)

Create new migration:

$ apistar makemigrations
Migration `0002_migration_201802142308` has been created.
Line 25: Value '' is selected as the default value for field tweet.price3 since the field is not null
Line 27: Check the field tweet.price2 are correctly converted to string
Line 36: Check the field tweet.price2 are correctly converted to integer

List migrations:

$ apistar listmigrations
[X] 0001_migration_201802142130
[ ] 0002_migration_201802142308

Show migration operations:

$ apistar showmigrations
[ ] 0002_migration_201802142308:
  SQL> ALTER TABLE "tweet" ADD COLUMN "price3" VARCHAR(200) []
  SQL> ALTER TABLE "tweet" RENAME COLUMN "f1" TO "old__f1" []
  SQL> ALTER TABLE "tweet" ADD COLUMN "f1" VARCHAR(20) []
  SQL> ALTER TABLE "tweet" RENAME COLUMN "price2" TO "old__price2" []
  SQL> ALTER TABLE "tweet" ADD COLUMN "price2" VARCHAR(200) []
  SQL> UPDATE "tweet" SET "price3" = %s WHERE ("price3" IS %s) ['', None]
  SQL> UPDATE "tweet" SET "price2" = CAST("old__price2" AS VARCHAR) WHERE ("old__price2" IS NOT %s) [None]
  SQL> UPDATE "tweet" SET "f1" = SUBSTRING("old__f1", %s, %s) WHERE ("old__f1" IS NOT %s) [1, 20, None]
  SQL> ALTER TABLE "tweet" DROP COLUMN "old__f1" []
  SQL> ALTER TABLE "tweet" DROP COLUMN "old__price2" []
  SQL> ALTER TABLE "tweet" ALTER COLUMN "price3" SET NOT NULL []
  SQL> ALTER TABLE "tweet" ALTER COLUMN "f1" SET NOT NULL []
  SQL> ALTER TABLE "tweet" ALTER COLUMN "price2" SET NOT NULL []
  PY>  set_done('0002_migration_201802142308')

Run migrations:

$ apistar migrate
[X] 0002_migration_201802142308

$ apistar listmigrations
[X] 0001_migration_201802142130
[X] 0002_migration_201802142308

Rollback migrations:

$ apistar showmigrations --to 1
[X] 0002_migration_201802142308:
  SQL> ALTER TABLE "tweet" RENAME COLUMN "price2" TO "old__price2" []
  SQL> ALTER TABLE "tweet" ADD COLUMN "price2" INTEGER []
  SQL> ALTER TABLE "tweet" RENAME COLUMN "f1" TO "old__f1" []
  SQL> ALTER TABLE "tweet" ADD COLUMN "f1" VARCHAR(50) []
  SQL> UPDATE "tweet" SET "price2" = CAST("old__price2" AS INTEGER) WHERE ("old__price2" IS NOT %s) [None]
  SQL> UPDATE "tweet" SET "f1" = SUBSTRING("old__f1", %s, %s) WHERE ("old__f1" IS NOT %s) [1, 50, None]
  SQL> ALTER TABLE "tweet" DROP COLUMN "price3" []
  SQL> ALTER TABLE "tweet" DROP COLUMN "old__price2" []
  SQL> ALTER TABLE "tweet" DROP COLUMN "old__f1" []
  SQL> ALTER TABLE "tweet" ALTER COLUMN "price2" SET NOT NULL []
  SQL> ALTER TABLE "tweet" ALTER COLUMN "f1" SET NOT NULL []
  PY>  set_undone('0002_migration_201802142308')

$ apistar migrate --to 1
[ ] 0002_migration_201802142308

$ apistar listmigrations
[X] 0001_migration_201802142130
[ ] 0002_migration_201802142308

$ apistar showmigrations --to zero
[X] 0001_migration_201802142130:
  SQL> DROP TABLE "tweet" []
  PY>  set_undone('0001_migration_201802142130')

To control where the migrations are created, you can specify migrate_dir and migrate_table settings (for each database). Default values are migrations and migratehistory.

Database use

To interact with the database, use the Session component. This will automatically handle commit/rollback behavior, depending on if the view returns normally, or raises an exception:

from apistar_peewee import Session


def create_customer(session: Session, name: str):
    customer = session.Customer(name=name)
    customer.save()
    return {'id': customer.id, 'name': customer.name}


def list_customers(session: Session):
    customers = session.Customer.select()
    return [
        {'id': customer.id, 'name': customer.name}
        for customer in customers
    ]

# and using another_db
def list_another_customers(session: Session['another_db']):
    customers = session.AnotherCustomer.select()
    return [
        {'id': customer.id, 'name': customer.name}
        for customer in customers
    ]

In addition, you can use Database instance directly:

from apistar_peewee import Database


def create_another_customers(db: Database['another_db'], name: str):
    with db.execution_context():
        customer = AnotherCustomer.create(name=name)
    return {'id': customer.id, 'name': customer.name}

For a working minimal example see /examples/app.py.