Skip to content

PwPd module

PwPd - PeeweePydantic. Module with adapters for transfering Peewee models to Pydantic models (a.k.a. serializer).

PwPdModel

Base class for PwPd models adapters.

Inherits Pydantic BaseModel and thus supports Pydantic features.

Config

Same as Pydantic models, behaviour of PwPdModel can be controlled via the Config class on a model. For available Pydantic options refer to Pydantic documentation.

Next Pydantic config options are set on PwPdModel:

  • orm_mode = True - Required to work with ORM model such as Peewee.
  • extra = 'forbid' - Will cause validation to fail if extra attributes are included.
  • getter_dict = PwPdGetterDict - Custom getter dict to handle backrefs.

Additional PwPd options:

  • pw_model: Type[peewee.Model]

    Required. Used to specify Peewee model for adapter.

  • pw_fields: set

    Set of PeeWee model fields to add to the Pydantic model. If not specified - all fields are used.

  • pw_exclude: set

    Set of PeeWee model fields to exclude from the the Pydantic model. If not specified - no fields are excluded.

  • pw_exclude_pk: bool

    Default - False. Whether to exclude primary key field from Pydantic model or not. Used for "write" models (create/update).

  • pw_nest_fk: bool

    Default - False. Whether to nest model data by foreign key or only return it's primary key value.

  • pw_nest_backrefs: bool

    Default - False. Whether to nest backrefs data or ignore backrefs.

  • pw_all_optional: bool

    Default - False. Wheter to set all fields optional or not. Used for partial update models, where any number of fields can be specified.

Creating PwPd model

Defining model class

You can define a model class using PwPdModel as a base class. Defining a PwPdModel is similar to defining Pydantic model. The only difference is Config options and automated definition of fields. You only need to define fields which behaviour you want to change.

It is required to set pw_model option in Config class.

Minimal usage example:

class CucumberPwPdModel(PwPdModel):
    class Config:
        pw_model: peewee.Model = Cucumber

More complex example:

import peewee as pw
from fastapiwee.pwpd import PwPdModel

DB = pw.SqliteDatabase(':memory:')


class TestModel(pw.Model):
    id = pw.AutoField()
    text = pw.TextField()
    number = pw.IntegerField(null=True)
    is_test = pw.BooleanField(default=True)

    class Meta:
        database = DB


# Define a PwPdModel (a.k.a. serializer)
class TestPwPdModel(PwPdModel):
    text: str = 'Something default'

    class Config:
        pw_model = TestModel
        pw_exclude_pk = True


# `text` field now has a default value and not required to specify
validated_data = TestPwPdModel(number=23)
new_instance = TestModel(**validated_data.dict())

assert new_instance.text == 'Something default'
assert new_instance.number == 23

Using make_serializer class method

make_serializer method can be used to create a generic Pydantic model from Peewee model. Method arguments can be used to override any of the Config options.

Usage: PwPdModel.make_serializer(peewee.Model, **config_options)

Example:

  • Define a model:

    import peewee as pw
    
    DB = pw.SqliteDatabase('/tmp/fastapiwee_example.db')
    
    
    class TestModel(pw.Model):
        id = pw.AutoField()
        text = pw.TextField()
        number = pw.IntegerField(null=True)
        is_test = pw.BooleanField(default=True)
    
        class Meta:
            database = DB
    
  • Make a simple serializer and try it:

    import peewee as pw
    from fastapiwee.pwpd import PwPdModel
    
    DB = pw.SqliteDatabase(':memory:')
    
    
    class TestModel(pw.Model):
        id = pw.AutoField()
        text = pw.TextField()
        number = pw.IntegerField(null=True)
        is_test = pw.BooleanField(default=True)
    
        class Meta:
            database = DB
    
    
    test_instance = TestModel(
        id=1,
        text='Cucumber',
        number=123,
    )
    
    # Make a simple serializer
    serializer = PwPdModel.make_serializer(TestModel)
    
    # Try it
    data = serializer.from_orm(test_instance)
    assert data.dict() == {
        'id': 1,
        'text': 'Cucumber',
        'number': 123,
        'is_test': True,
    }
    
  • Make a customized serializer and try it:

    import peewee as pw
    from fastapiwee.pwpd import PwPdModel
    
    DB = pw.SqliteDatabase(':memory:')
    
    
    class TestModel(pw.Model):
        id = pw.AutoField()
        text = pw.TextField()
        number = pw.IntegerField(null=True)
        is_test = pw.BooleanField(default=True)
    
        class Meta:
            database = DB
    
    
    test_instance = TestModel(
        id=1,
        text='Cucumber',
        number=123,
    )
    
    # Make a simple serializer
    serializer = PwPdModel.make_serializer(TestModel)
    
    # Try it
    data = serializer.from_orm(test_instance)
    assert data.dict() == {
        'id': 1,
        'text': 'Cucumber',
        'number': 123,
        'is_test': True,
    }
    
    # Make customized serializer
    serializer = PwPdModel.make_serializer(
        TestModel,
        pw_exclude_pk=True,
        pw_exclude={'is_test'},
        anystr_lower=True
    )
    
    # Try it
    data = serializer.from_orm(test_instance)
    assert data.dict() == {'text': 'cucumber', 'number': 123}
    

Other base PwPd models

Module also contains another base classes that are inherit default PwPdModel (thus make_serializer can be used on them as well). The only difference is a default Config values.

PwPdWriteModel

Base to create models for write actions (create/update). Excludes primary key field, will not nest foreign keys and backrefs.

Has next config:

class Config:
    pw_exclude_pk = True
    pw_nest_fk = False
    pw_nest_backrefs = False

PwPdPartialUpdateModel

Base to create models for partial update actions (e.g. PATCH). Inherits config from PwPdWriteModel, but all fields will be optional.

Has next config:

class Config:
    pw_all_optional = True

Factory

PwPdModelFactory class can be used to create "read" and "write" PwPd models for a single Peewee model.

Usage:

from fastapiwee.pwpd import PwPdModelFactory

pwpd_factory = PwPdModelFactory(peewee.Model)

# equals to PwPdModel.make_serializer(peewee.Model)
read_serializer = pwpd_factory.read_pd()

# equals to PwPdWriteModel.make_serializer(peewee.Model)
write_serializer = pwpd_factory.write_pd()