Inheritance¶
By default, re-using SQLAlchemy models through inheritance is not simple as
SQLAlchemy uses inheritance for other purposes. OpenAlchemy supports
model inheritance using the allOf statement from OpenAPI. Currently
column and model inheritance is supported.
See also
- SQLAlchemy inheritance documentation
Documentation for SQLAlchemy inheritance.
Column Inheritance¶
For columns, the main purpose of using inheritance through allOf is to
re-use elements of a base column definition but customize certain properties.
For example, you might have an integer id column for many models that
is quite similar except for the description. Or you might have a string
name column on many models but where the description and example might
differ. For example, the following specification defines a base schema for the
id and name columns and re-uses them for the Employee
and Division models with some changes to the description, example or
both.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | openapi: "3.0.0"
info:
title: Test Schema
description: API to illustrate allOf usage for columns.
version: "0.1"
paths:
/employee:
get:
summary: Used to retrieve all employees.
responses:
200:
description: Return all employees from the database.
content:
application/json:
schema:
type: array
items:
"$ref": "#/components/schemas/Employee"
/division:
get:
summary: Used to retrieve all divisions.
responses:
200:
description: Return all divisions from the database.
content:
application/json:
schema:
type: array
items:
"$ref": "#/components/schemas/Division"
components:
schemas:
IdBase:
type: integer
description: Base for the id schema of an object.
example: 0
x-primary-key: true
NameBase:
type: string
description: The name of the object.
example: Object 1.
Employee:
description: Person that works for a company.
type: object
x-tablename: employee
properties:
id:
allOf:
- "$ref": "#/components/schemas/IdBase"
- description: Unique identifier for the employee.
name:
allOf:
- "$ref": "#/components/schemas/NameBase"
- description: The name of the employee.
example: David Andersson
salary:
type: number
description: The amount of money the employee is paid.
example: 1000000.00
Division:
description: A part of a company.
type: object
x-tablename: division
properties:
id:
allOf:
- "$ref": "#/components/schemas/IdBase"
- description: Unique identifier for the division.
name:
allOf:
- "$ref": "#/components/schemas/NameBase"
- description: The name of the division.
example: Engineering.
|
The SQLAlchemy models might then look like:
1 2 3 | from open_alchemy import init_yaml
init_yaml("column-example-spec.yml", models_filename="column_models_auto.py")
|
Any duplicate properties are overridden by subsequent entries in allOf.
For example, if all entries have the description property, the
description from the last entry is actually used.
Model Inheritance¶
A similar feature is also supported for models. This allows, for example, to
define a base model that has an id and name. Then other models
with id and name columns can use the allOf feature to
copy those columns and add any model specific columns. This reduces duplication
in specifications. For example, the following specification defines an
IdNameBase model with id and name columns.
Employee and Division also required the columns but the
description and x-tablename needs to be different. By using
allOf they can copy the id and name columns from
IdNameBase and define their own description and
tablename.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | openapi: "3.0.0"
info:
title: Test Schema
description: API to illustrate OpenAlchemy MVP.
version: "0.1"
paths:
/employee:
get:
summary: Used to retrieve all employees.
responses:
200:
description: Return all employees from the database.
content:
application/json:
schema:
type: array
items:
"$ref": "#/components/schemas/Employee"
/division:
get:
summary: Used to retrieve all divisions.
responses:
200:
description: Return all divisions from the database.
content:
application/json:
schema:
type: array
items:
"$ref": "#/components/schemas/Division"
components:
schemas:
IdNameBase:
description: Base schema with an id and name column.
type: object
properties:
id:
type: integer
description: Unique identifier for the object.
example: 0
x-primary-key: true
name:
type: string
description: The name of the object.
example: Object 1.
Division:
allOf:
- "$ref": "#/components/schemas/IdNameBase"
- description: A part of a company.
x-tablename: division
Employee:
allOf:
- "$ref": "#/components/schemas/IdNameBase"
- description: Person that works for a company.
x-tablename: employee
type: object
properties:
salary:
type: number
description: The amount of money the employee is paid.
example: 1000000.00
|
The SQLAlchemy models might then look like:
1 2 3 | from open_alchemy import init_yaml
init_yaml("model-example-spec.yml", models_filename="model_models_auto.py")
|
Similar rules as for columns apply for duplicate properties in allOf
entries with one difference. The required property is treated as an
aggregate of all entries. For example, if the first entry has id and
the second entry has name in the required list, the final specification
has both id and name in the required list.
See also
References shows how to reference to other schemas.
Joined Table Inheritance¶
SQLAlchemy includes a feature where a model class hierarchy is implemented by
giving each class it’s own table. For example, an Employee might have
an id, name and type. Then a Manager model
might be defined that derives from Employee and adds the
manager_data column. This is also supported by OpenAlchemy through a
combination of the x-inherits and x-kwargs extension
properties. The x-kwargs has already been discussed here:
Miscellaneous Model Arguments and will be used to define some special model parameters to
instruct SQLAlchemy how to map Manager to Employee.
x-inherits¶
The x-inherits extension property is used to indicate to OpenAlchemy
that a schema inherits from another schema. The following values are supported:
boolean:true: Indicates that the schema inherits from the closest schema that it has a$refto that can be constructed. Object schemas with thex-tablenameorx-inheritsare those that generally can be constructed.false: Indicates that the schema does not inherit.
string: The name of the parent schema. The schema must have a$refthat links it to the schema with the name ofx-inherits.
In any case, if a schema inherits from another schema, there must be a
$ref linking the two schemas. That can be contained in allOf
and could be behind any number of nested $ref.
See also
References shows how to reference to other schemas.
x-kwargs¶
The required __mapper_args__ must be added using x-kwargs. For
example, for Employee:
1 2 3 4 5 6 7 | Employee:
type: object
...
x-kwargs:
__mapper_args__:
polymorphic_on: type
polymorphic_identity: employee
|
And for Manager:
1 2 3 4 5 6 | Manager:
type: object
...
x-kwargs:
__mapper_args__:
polymorphic_identity: manager
|
Example¶
The following shows the Employee and Manager schemas required
to define joined table inheritance in OpenAlchemy:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | Employee:
type: object
x-tablename: employee
properties:
id:
type: integer
x-primary-key: true
...
type:
type: string
description: The type of the employee.
example: employee
x-kwargs:
__mapper_args__:
polymorphic_on: type
polymorphic_identity: employee
Manager:
allOf:
- $ref: "#/components/schemas/Employee"
- x-inherits: true
x-tablename: manager
type: object
properties:
id:
type: integer
x-primary-key: true
x-foreign-key: employee.id
manager_data:
type: string
x-kwargs:
__mapper_args__:
polymorphic_identity: manager
|
See also
- Joined Table
Full example for joined table inheritance.
- SQLAlchemy joined table inheritance documentation
Documentation for SQLAlchemy joined table inheritance.
Single Table Inheritance¶
Single table inheritance is very similar to Joined Table Inheritance
with the difference that all classes are linked to the same table and there is
no foreign key relationship between the models. The following shows the
Employee and Manager schemas required to define single table
inheritance in OpenAlchemy:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | Employee:
type: object
x-tablename: employee
properties:
id:
type: integer
x-primary-key: true
...
type:
type: string
description: The type of the employee.
example: employee
x-kwargs:
__mapper_args__:
polymorphic_on: type
polymorphic_identity: employee
Manager:
allOf:
- $ref: "#/components/schemas/Employee"
- x-inherits: true
type: object
properties:
manager_data:
type: string
x-kwargs:
__mapper_args__:
polymorphic_identity: manager
|
See also
- Single Table
Full example for single table inheritance.
- SQLAlchemy single table inheritance documentation
Documentation for SQLAlchemy single table inheritance.