Skip to content

Commit c62dac7

Browse files
author
David Andersson
committed
Update documentation
1 parent 72fc67d commit c62dac7

File tree

4 files changed

+122
-10
lines changed

4 files changed

+122
-10
lines changed

docs/source/examples/relationship/many_to_many.rst

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ assigned to a project.
1414
`SQLAlchemy Many to Many <https://docs.sqlalchemy.org/en/13/orm/basic_relationships.html#many-to-many>`_
1515
SQLAlchemy documentation for many to many relationships.
1616

17-
The following example defines a many to many relationship between *Employee*
18-
and *Project*:
17+
The following example defines a many to many relationship between
18+
:samp:`Employee` and :samp:`Project`:
1919

2020
.. literalinclude:: ../../../../examples/relationship/many_to_many/example-spec.yml
2121
:language: yaml
@@ -39,3 +39,42 @@ OpenAlchemy will generate the following typed models:
3939
.. literalinclude:: ../../../../examples/relationship/many_to_many/models_auto.py
4040
:language: python
4141
:linenos:
42+
43+
Custom Association Schema
44+
-------------------------
45+
46+
OpenAlchemy also supports customization of the association schema that
47+
implements the many-to-many relationship. This means that the schema can be
48+
changed to include, for example, a column tracking when the association was
49+
established.
50+
51+
.. seealso::
52+
53+
:ref:`custom-association`
54+
OpenAlchemy documentation for many to many relationships with a custom
55+
association schema.
56+
57+
The following example defines a schema for the association:
58+
59+
.. literalinclude:: ../../../../examples/relationship/many_to_many/pre-defined-example-spec.yml
60+
:language: yaml
61+
:linenos:
62+
63+
The following file uses OpenAlchemy to generate the SQLAlchemy models:
64+
65+
.. literalinclude:: ../../../../examples/relationship/many_to_many/pre_defined_models.py
66+
:language: python
67+
:linenos:
68+
69+
The SQLAlchemy models generated by OpenAlchemy are equivalent to the following
70+
traditional models file:
71+
72+
.. literalinclude:: ../../../../examples/relationship/many_to_many/pre_defined_models_traditional.py
73+
:language: python
74+
:linenos:
75+
76+
OpenAlchemy will generate the following typed models:
77+
78+
.. literalinclude:: ../../../../examples/relationship/many_to_many/pre_defined_models_auto.py
79+
:language: python
80+
:linenos:

docs/source/technical_details/relationships.rst

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -499,3 +499,50 @@ dictionary::
499499

500500
Indicating that the project is being worked on by the employees with an id of
501501
*1* and *3*.
502+
503+
.. _custom-association:
504+
505+
Custom Association Schema
506+
-------------------------
507+
508+
OpenAlchemy supports customizing the association schema. This is useful to,
509+
for example, add columns tracking when the association between two objects
510+
was first established.
511+
512+
To define a custom association schema, define a schema that has an
513+
:samp:`x-tablename` that is the same as the :samp:`x-secondary` value of the
514+
many-to-many relationship. The following rules apply to the schema (which are
515+
enforced):
516+
517+
#. Any properties that are primary keys must also be one of the properties
518+
establishing a foreign key relationship to the child or the parent.
519+
#. At most 2 primary key properties can be defined.
520+
#. The :samp:`type`, :samp:`format` and :samp:`maxLength` of the foreign key
521+
property establishing one side of the many-to-many relationship must match
522+
the primary key property of the object on that side of the relationship
523+
(including whether they are defined).
524+
525+
OpenAlchemy will check for any missing foreign key properties and add them in
526+
automatically. For example, if an association only defines one side of a
527+
many-to-many relationship, OpenAlchemy will automatically generate a property
528+
for the other side.
529+
530+
Custom association schemas can define any other properties that are not
531+
primary keys. Note the following to ensure smooth operations:
532+
533+
* Any additional columns should somehow be generated by the server, for
534+
example, through a server default of the current time. This ensures that
535+
SQLAlchemy can automatically generate entries into the table to establish a
536+
many-to-many link between two objects.
537+
* It is possible to define relationships to the parent and child objects.
538+
However, not all of the usual relationship functionality is supported, for
539+
more information check here:
540+
`SQLAlchemy association object documentation <https://docs.sqlalchemy.org/en/13/orm/basic_relationships.html#association-object>`_
541+
542+
The following shows an example where the :samp:`Employee` side of the
543+
association schema has been defined. OpenAlchemy will automatically generate
544+
the :samp:`Project` side before constructing the model.
545+
546+
.. literalinclude:: ./relationships/many_to_many/custom_association.yaml
547+
:language: yaml
548+
:linenos:
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
Project:
2+
type: object
3+
x-tablename: project
4+
...
5+
properties:
6+
id:
7+
type: integer
8+
x-primary-key: true
9+
...
10+
Employee:
11+
type: object
12+
x-tablename: employee
13+
...
14+
properties:
15+
id:
16+
type: integer
17+
x-primary-key: true
18+
...
19+
projects:
20+
type: array
21+
items:
22+
allOf:
23+
- "$ref": "#/components/schemas/Project"
24+
- x-secondary: employee_project
25+
EmployeeProject:
26+
type: object
27+
x-tablename: employee_project
28+
...
29+
properties:
30+
employee_id:
31+
type: integer
32+
x-primary-key: true
33+
x-foreign-key: employee.id
34+
...

examples/relationship/many_to_many/pre_defined_models_traditional.py

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,6 @@
44
Base = declarative_base()
55

66

7-
employee_project = sa.Table(
8-
"employee_project",
9-
Base.metadata,
10-
sa.Column("project_id", sa.Integer, sa.ForeignKey("project.id")),
11-
sa.Column("employee_id", sa.Integer, sa.ForeignKey("employee.id")),
12-
)
13-
14-
157
class Project(Base):
168
"""A large sized business objective."""
179

0 commit comments

Comments
 (0)