Marshmallow-Peewee
Peewee ORM integration for the
Marshmallow (de)serialization
library. One Meta option turns a peewee model into a marshmallow schema.
Requirements
- python >= 3.11
- marshmallow >= 4, < 5 (marshmallow 3 is not supported)
- peewee
Installation
$ pip install marshmallow-peewee
Quickstart
import datetime as dt
import marshmallow as ma
import peewee as pw
db = pw.SqliteDatabase(":memory:")
class Role(pw.Model):
name = pw.CharField(255, default="user")
class Meta:
database = db
class User(pw.Model):
created = pw.DateTimeField(default=dt.datetime.now)
name = pw.CharField(255)
title = pw.CharField(127, null=True)
active = pw.BooleanField(default=True)
rating = pw.IntegerField(default=0)
role = pw.ForeignKeyField(Role)
class Meta:
database = db
db.create_tables([Role, User])
from marshmallow_peewee import ModelSchema
class UserSchema(ModelSchema):
class Meta:
model = User
role = Role.create()
user = User.create(name="Mike", role=role)
data = UserSchema().dump(user)
# {
# "id": "1",
# "created": "2026-01-01T12:00:00",
# "name": "Mike",
# "title": None,
# "active": True,
# "rating": 0,
# "role": "1",
# }
# The primary key is dump-only, so drop it when loading a full dump.
user = UserSchema().load(data, unknown=ma.EXCLUDE)
assert user.name == "Mike"
ModelSchema generates a marshmallow field for every peewee field when the
schema class is created. Fields declared on the schema class override generated
ones. Without Meta.model the schema behaves like a regular
marshmallow.Schema.
Meta options
| Option | Default | Description |
|---|---|---|
model |
None |
Peewee model to map. |
model_converter |
DefaultConverter |
Converter class that builds the fields. |
dump_only_pk |
True |
Make the integer primary key dump-only. |
string_keys |
True |
Serialize integer keys, including foreign keys, as strings. |
id_keys |
False |
Use the column name (role_id) instead of the field name (role) for foreign keys. |
Options are resolved in this order: the schema Meta, the base schema Meta,
then global defaults. Standard marshmallow options (fields,
exclude, unknown, dateformat, and others) keep working on top of the
generated fields.
class UserSchema(ModelSchema):
class Meta:
model = User
string_keys = False
id_keys = True
dump_only_pk = False
Field mapping
| Peewee | Marshmallow |
|---|---|
CharField |
String with Length |
TextField, FixedCharField |
String |
IntegerField, BigIntegerField, SmallIntegerField |
Integer |
AutoField |
String or Integer (see below) |
FloatField, DoubleField |
Float |
DecimalField |
Decimal (dumped as a string) |
DateTimeField, DateField, TimeField |
DateTime, Date, Time |
TimestampField |
DateTime |
IPField |
String |
BooleanField |
Boolean |
UUIDField |
UUID |
ForeignKeyField, DeferredForeignKey |
ForeignKey |
| anything else | Raw |
A few details that are not obvious from the table:
AutoFieldbecomesStringwhenstring_keysis on andIntegerotherwise. It is dump-only unlessdump_only_pkis off. Any integer primary key (pw.IntegerField(primary_key=True)) behaves the same way.null=Truesetsallow_noneandload_default=None. A non-null field with a default gets that default asload_default; a non-null field without a default is required.choicesare turned into aOneOfvalidator,help_textis stored infield.metadata["description"].Decimalfields dump as strings soSchema.dumps()andjson.dumps()work; loading accepts a string, an int or a float.- Foreign keys are serialized from
obj.__data__, so dumping a foreign key does not query the related table.
Foreign keys
By default a foreign key is dumped as its raw value: a string when
string_keys is on, an integer otherwise. With id_keys=True the field is named
after the column (role_id). Both forms load back into the same model. On load
a foreign key accepts the related model instance or a value the related primary
key can hold; anything else is a ValidationError.
Related builds a nested schema from the related model and lets you dump and
load the whole object:
from marshmallow_peewee import Related
class UserSchema(ModelSchema):
role = Related(unknown=ma.EXCLUDE)
class Meta:
model = User
data = UserSchema().dump(user)
# {..., "role": {"id": "1", "name": "user"}}
user = UserSchema().load(data, unknown=ma.EXCLUDE)
assert isinstance(user.role, Role)
Nested schemas dump the primary key too, so pass unknown=ma.EXCLUDE to the
field if you load nested dumps back.
Related also accepts an explicit schema, and works for reverse relations
(for example Role.user_set = Related()); call Related() without arguments
only where Meta.model is available, otherwise the field cannot be initialized.
FKNested does the same but reads the related object from peewee's relation
cache (obj.__rel__) instead of querying. The relation must already be loaded,
for example with User.select(User, Role).join(Role) or by accessing
user.role before dumping. Otherwise the dump raises KeyError.
from marshmallow_peewee import FKNested
class UserSchema(ModelSchema):
role_data = FKNested(Role, only=("name",), attribute="role")
class Meta:
model = User
exclude = ("role",)
ForeignKey is the field class used for foreign key columns. Subclass it if you
need to change how a raw key is serialized.
Global defaults
from marshmallow_peewee import setup
setup(id_keys=True, string_keys=False) # Applies to schemas declared later
setup mutates process-wide defaults, so call it once at startup, not per
request or per schema. Unknown option names raise TypeError. Per-schema Meta options always win.
Custom conversion
Register a marshmallow field for a peewee field class:
import marshmallow as ma
import peewee as pw
from marshmallow_peewee import DefaultConverter
DefaultConverter.register(pw.BooleanField, ma.fields.String)
For more control, register a builder function. It receives the peewee field, the schema options, and the standard field parameters:
@DefaultConverter.register(pw.BooleanField)
def convert_boolean(field, opts, **params):
params["load_default"] = "yes"
return ma.fields.String(**params)
To change fields for one schema only, register on a converter subclass. The
subclass gets its own mapping; DefaultConverter is not affected:
class CustomConverter(DefaultConverter):
pass
CustomConverter.register(pw.BooleanField, ma.fields.String)
class UserSchema(ModelSchema):
class Meta:
model = User
model_converter = CustomConverter
The lookup walks the peewee field MRO, so subclasses of known fields are converted as their closest known parent.
Limitations
- Marshmallow 3 is not supported. Use marshmallow-peewee 5.x if you still need it.
Meta.fieldsandMeta.excludeonly filter fields that exist on the model or are declared on the schema. Marshmallow 4 removed implicit field creation.- A full dump contains the dump-only primary key, so loading it back requires
unknown=ma.EXCLUDEor removing the key. FKNesteddoes not trigger queries and requires a loaded relation.- Nested schemas are generated from models. Fetching the right rows is up to you.
Bug tracker
If you have any suggestions, bug reports or annoyances please report them to the issue tracker at https://github.com/klen/marshmallow-peewee/issues
Contributing
Development of the project happens at: https://github.com/klen/marshmallow-peewee
License
Licensed under a MIT License
Metadata
Release files for marshmallow-peewee 6.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| marshmallow_peewee-6.0.0.tar.gz | 9.6 kB | Without provenance | Details for marshmallow_peewee-6.0.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| marshmallow_peewee-6.0.0-py3-none-any.whl | Python 3 | none | any | Details for marshmallow_peewee-6.0.0-py3-none-any.whl |
Total release size: 20.8 kB
Release files / marshmallow_peewee-6.0.0.tar.gz
| Download URL | marshmallow_peewee-6.0.0.tar.gz |
|---|---|
| Size | 9.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
977f0670dc14c524745f3656c9d2dfba215e31e3fec52ad464ceabd5e15c3271
|
|
BLAKE2b-256 checksum How to use checksums |
a225512f1255743a4f2627c0f98a178c04b395fa0c1a54c92742e2ea3cb4eeca
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.13.7 {"installer":{"name":"uv","version":"0.13.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"26.04","id":"resolute","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / marshmallow_peewee-6.0.0-py3-none-any.whl
| Download URL | marshmallow_peewee-6.0.0-py3-none-any.whl |
|---|---|
| Size | 11.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
d849737cd703349950edbffd42a2a1f15300cee6c45a34eea5bf2602c6f018dd
|
|
BLAKE2b-256 checksum How to use checksums |
f1b6852076520e5374fbefc969625d88505017c769c1b62ba999dbd3c1f6d748
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.13.7 {"installer":{"name":"uv","version":"0.13.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"26.04","id":"resolute","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Security for marshmallow-peewee 6.0.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.