读读文档吧 - SQLAlchemy 2.0

ORM Mapped Class Overview icon-default.png?t=N7T8https://docs.sqlalchemy.org/en/20/orm/mapping_styles.html

The original mapping API is commonly referred to as “classical” style, whereas the more automated style of mapping is known as “declarative” style. SQLAlchemy now refers to these two mapping styles as imperative mapping and declarative mapping.

The Declarative Mapping is the typical way that mappings are constructed in modern SQLAlchemy. 

# flask_sqlalchemy的源码,说明它用的是Declarative Mapping
self.Model = self._make_declarative_base(model_class)
        """A SQLAlchemy declarative model class. Subclass this to define database
        models."""

The imperative mapping (总之先忽略这个方式就是了) form is a lesser-used form of mapping that originates from the very first releases of SQLAlchemy in 2006.  It's recommended that new users start with Declarative Table configuration.

Note that classes which are mapped with the Imperative approach are fully interchangeable with those mapped with the Declarative approach. Both systems ultimately create the same configuration, consisting of a Table, user-defined class, linked together with a Mapper object. (底层没区别) When we talk about “the behavior of Mapper”, this includes when using the Declarative system as well - it’s still used, just behind the scenes.

In the vast majority of common cases this is an instance of Table. For more advanced use cases, it may also refer to any kind of FromClause object, the most common alternative objects being the Subquery and Join object. (也可以和子查询、视图进行map)

The registry applies a default constructor, i.e. __init__ method, to all mapped classes that don’t explicitly have their own __init__ method. The behavior of this method is such that it provides a convenient keyword constructor that will accept as optional keyword arguments all the attributes that are named. (有一个默认的构造函数)

A class that includes an explicit __init__() method will maintain that method, and no default constructor will be applied. (自己定义了,就把默认的覆盖了)
 

Declarative Mapping Stylesicon-default.png?t=N7T8https://docs.sqlalchemy.org/en/20/orm/declarative_styles.html

继承(一般就用这个就好) The most common approach is to generate a “Declarative Base” class by subclassing the DeclarativeBase superclass.

装饰器 The decorator form of mapping is useful when combining a SQLAlchemy declarative mapping with other class instrumentation systems such as dataclasses and attrs, though note that SQLAlchemy 2.0 now features dataclasses integration with Declarative Base classes as well.

Table Configuration with Declarativeicon-default.png?t=N7T8https://docs.sqlalchemy.org/en/20/orm/declarative_tables.html

The mapped_column() 新特性 construct, which features additional ORM-specific configuration capabilities not present in the plain Column 旧的也能用 class, is then used within the class body to indicate columns in the table. 

each instance of mapped_column() will then be used to generate a Column object during this process, which will become part of the Table.columns collection of this Table object.

mapped_column() supersedes the use of Column()
This ORM-specific construct is intended first and foremost to be a drop-in replacement for the use of Column within Declarative mappings only, adding new ORM-specific convenience features such as the ability to establish mapped_column.deferred within the construct, and most importantly to indicate to typing tools such as Mypy and Pylance an accurate representation of how the attribute will behave at runtime at both the class level as well as the instance level. 

Users of legacy code should be aware that the Column form will always work in Declarative in the same way it always has. The different forms of attribute mapping may also be mixed within a single mapping on an attribute by attribute basis, so migration to the new form can be at any pace. 

Relationship Loading Techniques — SQLAlchemy 2.0 Documentationicon-default.png?t=N7T8https://docs.sqlalchemy.org/en/20/orm/queryguide/relationships.html

​多种方式控制对嵌套对象的加载 A big part of SQLAlchemy is providing a wide range of control over how related objects get loaded when querying. By “related objects” we refer to collections or scalar associations configured on a mapper using relationship(). This behavior can be configured at mapper construction time using the relationship.lazy parameter to the relationship() function 静态写死, as well as by using ORM loader options with the Select construct. 动态

三类方式

Lazy loading 延迟加载-简单-加载列表小心 refers to objects that are returned from a query without the related objects loaded at first. When the given collection or reference is first accessed on a particular object, an additional SELECT statement is emitted such that the requested collection is loaded.

Eager loading 一次完成、按需加载 refers to objects returned from a query with the related collection or scalar reference already loaded up front. The ORM achieves this either by augmenting the SELECT statement it would normally emit with a JOIN to load in related rows simultaneously, or by emitting additional SELECT statements after the primary one to load collections or scalar references at once.

“No” loading refers to the disabling of loading on a given relationship, either that the attribute is empty and is just never loaded, or that it raises an error when it is accessed, in order to guard against unwanted lazy loads.

细分方式

lazy loading -  is the default loading style 默认 for all relationship() constructs that don’t otherwise indicate the relationship.lazy option. 

select IN loading -  assembles the primary key identifiers of the parent objects into an IN clause, so that all members of related collections / scalar references are loaded at once by primary key. 貌似可以用来筛选relationship?

joined loading - this form of loading applies a JOIN to the given SELECT statement so that related rows are loaded in the same result set. 都给加载了啊

raise loading -  this form of loading is triggered at the same time a lazy load would normally occur, except it raises an ORM exception 某些情况下会抛异常? in order to guard against the application making unwanted lazy loads.

subquery loading - this form of loading emits a second SELECT statement which re-states the original query embedded inside of a subquery, then JOINs that subquery to the related table to be loaded to load all members of related collections / scalar references at once

write only loading - This collection-only loader style produces an alternative attribute instrumentation that never implicitly loads records from the database, instead only allowing WriteOnlyCollection.add(), WriteOnlyCollection.add_all() and WriteOnlyCollection.remove() methods. Querying the collection is performed by invoking a SELECT statement which is constructed using the WriteOnlyCollection.select() method.

dynamic loading - This is a 老东西 legacy collection-only loader style which produces a Query object when the collection is accessed, allowing custom SQL to be emitted against the collection’s contents. However, dynamic loaders will implicitly iterate the underlying collection in various circumstances which makes them less useful for managing truly large collections. Dynamic loaders are superseded by “write only” collections 用这个新的, which will prevent the underlying collection from being implicitly loaded under any circumstances.

# 定义时
children: Mapped[List["Child"]] = relationship(lazy="selectin")

# 查询时
stmt = select(Parent).options(joinedload(Parent.children))

The loader options can also be “chained” using method chaining to specify how loading should occur further levels deep. 层层深入​​​​​​​