基本關系模式
The imports used for each of the following sections is as follows:
下列的 import 語句,應用到接下來所有的代章節中:
from sqlalchemy import Table, Column, Integer, ForeignKey from sqlalchemy.orm import relationship from sqlalchemy.ext.declarative import declarative_base Base = declarative_base()
One To Many
A one to many relationship places a foreign key on the child table referencing the parent.
表示一對多的關系時,在子表類中通過 foreign key (外鍵)引用父表類。
relationship() is then specified on the parent, as referencing a collection of items represented by the child:
然后,在父表類中通過 relationship() 方法來引用子表的類:
class Parent(Base): __tablename__ = 'parent' id = Column(Integer, primary_key=True) children = relationship("Child") # 在父表類中通過 relationship() 方法來引用子表的類集合 class Child(Base): __tablename__ = 'child' id = Column(Integer, primary_key=True) parent_id = Column(Integer, ForeignKey('parent.id')) # 在子表類中通過 foreign key (外鍵)引用父表的參考字段
To establish a bidirectional relationship in one-to-many, where the “reverse” side is a many to one,
在一對多的關系中建立雙向的關系,這樣的話在對方看來這就是一個多對一的關系,
specify an additional relationship() and connect the two using the relationship.back_populates parameter:
在子表類中附加一個 relationship() 方法,並且在雙方的 relationship() 方法中使用 relationship.back_populates 方法參數:
class Parent(Base): __tablename__ = 'parent' id = Column(Integer, primary_key=True) children = relationship("Child", back_populates="parent") class Child(Base): __tablename__ = 'child' id = Column(Integer, primary_key=True) parent_id = Column(Integer, ForeignKey('parent.id')) parent = relationship("Parent", back_populates="children") # 子表類中附加一個 relationship() 方法 # 並且在(父)子表類的 relationship() 方法中使用 relationship.back_populates 參數
Child will get a parent attribute with many-to-one semantics.
這樣的話子表將會在多對一的關系中獲得父表的屬性
Alternatively, the backref option may be used on a single relationship() instead of using back_populates:
或者,可以在單一的 relationship() 方法中使用 backref 參數來代替 back_populates 參數:
class Parent(Base): __tablename__ = 'parent' id = Column(Integer, primary_key=True) children = relationship("Child", backref="parent") class Child(Base): __tablename__ = 'child' id = Column(Integer, primary_key=True) parent_id = Column(Integer, ForeignKey('parent.id'))
One To One
One To One is essentially a bidirectional relationship with a scalar attribute on both sides.
一對一是兩張表之間本質上的雙向關系。
To achieve this, the uselist flag indicates the placement of a scalar attribute instead of a collection on the “many” side of the relationship.
要做到這一點,只需要在一對多關系基礎上的父表中使用 uselist 參數來表示。
To convert one-to-many into one-to-one:
class Parent(Base): __tablename__ = 'parent' id = Column(Integer, primary_key=True) child = relationship("Child", uselist=False, back_populates="parent") class Child(Base): __tablename__ = 'child' id = Column(Integer, primary_key=True) parent_id = Column(Integer, ForeignKey('parent.id')) parent = relationship("Parent", back_populates="child")
To convert many-to-one into one-to-one:
class Parent(Base): __tablename__ = 'parent' id = Column(Integer, primary_key=True) child_id = Column(Integer, ForeignKey('child.id')) child = relationship("Child", back_populates="parent") class Child(Base): __tablename__ = 'child' id = Column(Integer, primary_key=True) parent = relationship("Parent", back_populates="child", uselist=False)
As always, the relationship.backref and backref() functions may be used in lieu of the relationship.back_populates approach; to specify uselist on a backref, use the backref() function:
同樣的,可以使用下面這種方式:
from sqlalchemy.orm import backref class Parent(Base): __tablename__ = 'parent' id = Column(Integer, primary_key=True) child_id = Column(Integer, ForeignKey('child.id')) child = relationship("Child", backref=backref("parent", uselist=False)) class Child(Base): __tablename__ = 'child' id = Column(Integer, primary_key=True) parent_id = Column(Integer, ForeignKey('parent.id'))
Many To Many
Many to Many adds an association table between two classes.
多對多關系會在兩個類之間增加一個關聯的表。
The association table is indicated by the secondary argument to relationship().
這個關聯的表在 relationship() 方法中通過 secondary 參數來表示。
Usually, the Table uses the MetaData object associated with the declarative base class,
通常的,這個表會通過 MetaData 對象來與聲明基類關聯,
so that the ForeignKey directives can locate the remote tables with which to link:
所以這個 ForeignKey 指令會使用鏈接來定位到遠程的表:
# 多對多關系中的兩個表之間的一個關聯表 association_table = Table('association', Base.metadata, Column('left_id', Integer, ForeignKey('left.id')), Column('right_id', Integer, ForeignKey('right.id')) ) class Parent(Base): __tablename__ = 'left' id = Column(Integer, primary_key=True) children = relationship("Child", secondary=association_table) # 在父表中的 relationship() 方法傳入 secondary 參數,其值為關聯表的表名 class Child(Base): __tablename__ = 'right' id = Column(Integer, primary_key=True)
For a bidirectional relationship, both sides of the relationship contain a collection.
雙向關系中,兩個表類都會包含這個集合。
Specify using relationship.back_populates, and for each relationship() specify the common association table:
指定使用 relationship.back_populates 參數,並且為每一個 relationship() 方法指定共用的關聯表:
association_table = Table('association', Base.metadata, Column('left_id', Integer, ForeignKey('left.id')), Column('right_id', Integer, ForeignKey('right.id')) ) class Parent(Base): __tablename__ = 'left' id = Column(Integer, primary_key=True) children = relationship( "Child", secondary=association_table, back_populates="parents") class Child(Base): __tablename__ = 'right' id = Column(Integer, primary_key=True) parents = relationship( "Parent", secondary=association_table, back_populates="children")
When using the backref parameter instead of relationship.back_populates, the backref will automatically use the same secondary argument for the reverse relationship:
當在父表類的 relationship() 方法中使用 backref參數代替 relationship.back_populates 時,backref 會自動的為子表類加載同樣的 secondary 參數。
association_table = Table('association', Base.metadata, Column('left_id', Integer, ForeignKey('left.id')), Column('right_id', Integer, ForeignKey('right.id')) ) class Parent(Base): __tablename__ = 'left' id = Column(Integer, primary_key=True) children = relationship("Child", secondary=association_table, backref="parents") class Child(Base): __tablename__ = 'right' id = Column(Integer, primary_key=True)
The secondary argument of relationship() also accepts a callable that returns the ultimate argument,
secondary 參數還能夠接收一個可調函數的最終返回值,
which is evaluated only when mappers are first used. Using this, we can define the association_table at a later point, as long as it’s available to the callable after all module initialization is complete:
class Parent(Base): __tablename__ = 'left' id = Column(Integer, primary_key=True) children = relationship("Child", secondary=lambda: association_table, backref="parents")
With the declarative extension in use, the traditional “string name of the table” is accepted as well, matching the name of the table as stored in Base.metadata.tables:
class Parent(Base): __tablename__ = 'left' id = Column(Integer, primary_key=True) children = relationship("Child", secondary="association", backref="parents")
