ColanderAlchemy¶
ColanderAlchemy helps you to automatically generate Colander schemas based on SQLAlchemy mapped classes.
Quick start¶
In order to get started with ColanderAlchemy, you can either use
colanderalchemy.setup_schema()
to automatically create and attach a
schema to a mapped class for you, or else you can use
colanderalchemy.SQLAlchemySchemaNode
to have more control over the
auto-generated schema.
The easiest way to get going is to set up an SQLAlchemy event listener. There are two ways in which to have schemas automatically generated for your models.
For individual SQLAlchemy models, configure the
colanderalchemy.setup_schema()
method to listen for themapper_configured
event for your model class:from sqlalchemy import event from colanderalchemy import setup_schema # MyModel is your SQLAlchemy model class event.listen(MyModel, 'mapper_configured', setup_schema)
This is simplest and most efficient option if you know specifically which models require Colander schemas attached.
To automatically create schemas for all mapped models, configure the
colanderalchemy.setup_schema()
method to listen for themapper_configured
event forsqlalchemy.orm.mapper
:from sqlalchemy import event from sqlalchemy.orm import mapper from colanderalchemy import setup_schema event.listen(mapper, 'mapper_configured', setup_schema)
Consider which Colander schemas you use directly because
setup_schema
will attach schemas to all models automatically. This may result in extra overhead from generating Colander schemas that you do not use.
In both cases, this will create a Colander schema from the given SQLAlchemy
model, and attach it to the given class as the attribute
__colanderalchemy__
. This event fires when the mapper for the given class
is fully configured.
Note
Keep in mind that you should configure the event listener as soon as possible in your application, especially if you’re using declarative definitions. Adding the above code immediately after your SQLAlchemy model class definition is advised.
By associating ColanderAlchemy
configuration with your mapped class, its
columns, and its relationships, you can tell ColanderAlchemy
how to
generate each and every part of your mapped schema - including things like
titles, descriptions, preparers, validators, widgets, and more. See
Configuring within SQLAlchemy models for more information on how to customise this process.
Usage¶
Beyond the event listener methodology above, you can use
colanderalchemy.setup_schema()
manually. Simply pass it a SQLAlchemy
mapped class like so:
from sqlalchemy import Column, Integer, String, Text
from sqlalchemy.ext.declarative import declarative_base
from colanderalchemy import setup_schema
Base = declarative_base()
class SomeClass(Base):
__tablename__ = 'some_table'
id = Column(Integer, primary_key=True)
name = Column(String(50))
biography = Column(Text())
setup_schema(None, SomeClass)
SomeClass.__colanderalchemy__ # A Colander schema for you to use
If you already have a mapped class available, you can just pass it as is - you don’t need to redefine another schema.
Also, if you’d like even more control over your generated schema, then
use colanderalchemy.SQLAlchemySchemaNode
directly like so:
from colanderalchemy import SQLAlchemySchemaNode
from my.project import SomeClass
schema = SQLAlchemySchemaNode(SomeClass,
includes=['name', 'biography'],
excludes=['id'],
title='Some class')
Or include custom field:
import deform
import colander
from colanderalchemy import SQLAlchemySchemaNode
from my.project import SomeClass
typ = colander.String()
widget = deform.widget.SelectWidget(values=(('foo', 'a'),
('bar', 'b'),
('baz', 'c')))
column = colander.SchemaNode(typ,
name='customfield',
widget=widget)
schema = SQLAlchemySchemaNode(SomeClass,
includes=['name', column, 'biography'],
excludes=['id'],
title='Some class')
Note the various arguments you can pass when creating your mapped schema -
you have full control over how the schema is generated and what fields
are included, which are excluded, and more. See the
colanderalchemy.SQLAlchemySchemaNode
API documentation for more
information. For more information you should read the section Examples
to see how use ColanderAlchemy.
In either situation, you can now pass the resulting Colander
schema to
anything that needs it. For instance, this works well with Deform
and you
can read more about this later in this documentation: Examples: using ColanderAlchemy with Deform.
How it works¶
ColanderAlchemy auto-generates Colander schemas following these rules:
The type of the schema is
colander.MappingSchema
,The schema has a
colander.SchemaNode
for eachsqlalchemy.Column
in the mapped object:
- The type of
colander.SchemaNode
is based on the type ofsqlalchemy.Column
- The
colander.SchemaNode
has a validator if thesqlalchemy.Column
is an instance of eithersqlalchemy.types.Enum
orsqlalchemy.types.String
.Enum
is checked withcolander.OneOf
andString
is checked withcolander.Length
- Customization stored in the
__colanderalchemy_config__
attribute of the SQLAlchemy type are applied.colander.SchemaNode
hasmissing=colander.required
except for the whendefault
is set,nullable=True
, there’s aserver_default
, or the field is an auto incrementing integer used as part of a primary key. Essentially it’s required unless SQLAlchemy can derive a value for you automatically if it’s missing.colander.SchemaNode
hasdefault=colander.null
unless there is a column default which is a static scalar value. Callable function defaults and server defaults are ignored for the purposes of generating a colander schema default value.- Customisations to the resulting
colander.SchemaNode
are applied, if defined as part of theinfo
structure on thesqlalchemy.Column
.The schema has a
colander.SchemaNode
for each relationship (sqlalchemy.orm.relationship
or those fromsqlalchemy.orm.backref
) in the mapped object:
The
colander.SchemaNode
hasmissing=None
- The type of
colander.SchemaNode
is:
- A
colander.Mapping
for ManyToOne and OneToOne relationships- A
colander.Sequence
ofcolander.Mapping
for ManyToMany and OneToMany relationships- Customisations to the resulting
colander.SchemaNode
are applied, if defined as part of theinfo
structure on thesqlalchemy.orm.relationship
.For both kind of relationships, the
colander.Mapping
is built recursively by applying this same set of rules to the mapped class referenced by the relationship.Customisations to the resulting
Colander
schema are applied using configuration stored in the__colanderalchemy_config__
attribute on the class definition.
Read the section Customization to see how change these rules and how to customize the Colander schema returned by ColanderAlchemy.