lazy load
lazy loads
+ lazy loading
In object relational mapping, a "lazy load" refers to an
attribute that does not contain its database-side value
for some period of time, typically when the object is
`PEP 249 - Python Database API Specification v2.0 <http://www.python.org/dev/peps/pep-0249/>`_
+ domain model
+
+ A domain model in problem solving and software engineering is a conceptual model of all the topics related to a specific problem. It describes the various entities, their attributes, roles, and relationships, plus the constraints that govern the problem domain.
+
+ (via Wikipedia)
+
+ .. seealso::
+
+ `Domain Model (wikipedia) <http://en.wikipedia.org/wiki/Domain_model>`_
unit of work
This pattern is where the system transparently keeps
clause is not possible, because the correlation can only proceed once the
original source rows from the enclosing statement's FROM clause are available.
+
ACID
ACID model
An acronym for "Atomicity, Consistency, Isolation,
on top of the RETURNING systems of these backends to provide a consistent
interface for returning columns. The ORM also includes many optimizations
that make use of RETURNING when available.
+
+ one to many
+ A style of :func:`~sqlalchemy.orm.relationship` which links
+ the primary key of the parent mapper's table to the foreign
+ key of a related table. Each unique parent object can
+ then refer to zero or more unique related objects.
+
+ The related objects in turn will have an implicit or
+ explicit :term:`many to one` relationship to their parent
+ object.
+
+ An example one to many schema (which, note, is identical
+ to the :term:`many to one` schema):
+
+ .. sourcecode:: sql
+
+ CREATE TABLE department (
+ id INTEGER PRIMARY KEY,
+ name VARCHAR(30)
+ )
+
+ CREATE TABLE employee (
+ id INTEGER PRIMARY KEY,
+ name VARCHAR(30),
+ dep_id INTEGER REFERENCES department(id)
+ )
+
+ The relationship from ``department`` to ``employee`` is
+ one to many, since many employee records can be associated with a
+ single department. A SQLAlchemy mapping might look like::
+
+ class Department(Base):
+ __tablename__ = 'department'
+ id = Column(Integer, primary_key=True)
+ name = Column(String(30))
+ employees = relationship("Employee")
+
+ class Employee(Base):
+ __tablename__ = 'employee'
+ id = Column(Integer, primary_key=True)
+ name = Column(String(30))
+ dep_id = Column(Integer, ForeignKey('department.id'))
+
+ .. seealso::
+
+ :term:`relationship`
+
+ :term:`many to one`
+
+ :term:`backref`
+
+ many to one
+ A style of :func:`~sqlalchemy.orm.relationship` which links
+ a foreign key in the parent mapper's table to the primary
+ key of a related table. Each parent object can
+ then refer to exactly zero or one related object.
+
+ The related objects in turn will have an implicit or
+ explicit :term:`one to many` relationship to any number
+ of parent objects that refer to them.
+
+ An example many to one schema (which, note, is identical
+ to the :term:`one to many` schema):
+
+ .. sourcecode:: sql
+
+ CREATE TABLE department (
+ id INTEGER PRIMARY KEY,
+ name VARCHAR(30)
+ )
+
+ CREATE TABLE employee (
+ id INTEGER PRIMARY KEY,
+ name VARCHAR(30),
+ dep_id INTEGER REFERENCES department(id)
+ )
+
+
+ The relationship from ``employee`` to ``department`` is
+ many to one, since many employee records can be associated with a
+ single department. A SQLAlchemy mapping might look like::
+
+ class Department(Base):
+ __tablename__ = 'department'
+ id = Column(Integer, primary_key=True)
+ name = Column(String(30))
+
+ class Employee(Base):
+ __tablename__ = 'employee'
+ id = Column(Integer, primary_key=True)
+ name = Column(String(30))
+ dep_id = Column(Integer, ForeignKey('department.id'))
+ department = relationship("Department")
+
+ .. seealso::
+
+ :term:`relationship`
+
+ :term:`one to many`
+
+ :term:`backref`
+
+ backref
+ bidirectional relationship
+ An extension to the :term:`relationship` system whereby two
+ distinct :func:`~sqlalchemy.orm.relationship` objects can be
+ mutually associated with each other, such that they coordinate
+ in memory as changes occur to either side. The most common
+ way these two relationships are constructed is by using
+ the :func:`~sqlalchemy.orm.relationship` function explicitly
+ for one side and specifying the ``backref`` keyword to it so that
+ the other :func:`~sqlalchemy.orm.relationship` is created
+ automatically. We can illustrate this against the example we've
+ used in :term:`one to many` as follows::
+
+ class Department(Base):
+ __tablename__ = 'department'
+ id = Column(Integer, primary_key=True)
+ name = Column(String(30))
+ employees = relationship("Employee", backref="department")
+
+ class Employee(Base):
+ __tablename__ = 'employee'
+ id = Column(Integer, primary_key=True)
+ name = Column(String(30))
+ dep_id = Column(Integer, ForeignKey('department.id'))
+
+ A backref can be applied to any relationship, including one to many,
+ many to one, and :term:`many to many`.
+
+ .. seealso::
+
+ :term:`relationship`
+
+ :term:`one to many`
+
+ :term:`many to one`
+
+ :term:`many to many`
+
+ many to many
+ A style of :func:`sqlalchemy.orm.relationship` which links two tables together
+ via an intermediary table in the middle. Using this configuration,
+ any number of rows on the left side may refer to any number of
+ rows on the right, and vice versa.
+
+ A schema where employees can be associated with projects:
+
+ .. sourcecode:: sql
+
+ CREATE TABLE employee (
+ id INTEGER PRIMARY KEY,
+ name VARCHAR(30)
+ )
+
+ CREATE TABLE project (
+ id INTEGER PRIMARY KEY,
+ name VARCHAR(30)
+ )
+
+ CREATE TABLE employee_project (
+ employee_id INTEGER PRIMARY KEY,
+ project_id INTEGER PRIMARY KEY,
+ FOREIGN KEY employee_id REFERENCES employee(id),
+ FOREIGN KEY project_id REFERENCES project(id)
+ )
+
+ Above, the ``employee_project`` table is the many-to-many table,
+ which naturally forms a composite primary key consisting
+ of the primary key from each related table.
+
+ In SQLAlchemy, the :func:`sqlalchemy.orm.relationship` function
+ can represent this style of relationship in a mostly
+ transparent fashion, where the many-to-many table is
+ specified using plain table metadata::
+
+ class Employee(Base):
+ __tablename__ = 'employee'
+
+ id = Column(Integer, primary_key)
+ name = Column(String(30))
+
+ projects = relationship(
+ "Project",
+ secondary=Table('employee_project', Base.metadata,
+ Column("employee_id", Integer, ForeignKey('employee.id'),
+ primary_key=True),
+ Column("project_id", Integer, ForeignKey('project.id'),
+ primary_key=True)
+ ),
+ backref="employees"
+ )
+
+ class Project(Base):
+ __tablename__ = 'project'
+
+ id = Column(Integer, primary_key)
+ name = Column(String(30))
+
+ Above, the ``Employee.projects`` and back-referencing ``Project.employees``
+ collections are defined::
+
+ proj = Project(name="Client A")
+
+ emp1 = Employee(name="emp1")
+ emp2 = Employee(name="emp2")
+
+ proj.employees.extend([emp1, emp2])
+
+ .. seealso::
+
+ :term:`association relationship`
+
+ :term:`relationship`
+
+ :term:`one to many`
+
+ :term:`many to one`
+
+ relationship
+ relationships
+ A connecting unit between two mapped classes, corresponding
+ to some relationship between the two tables in the database.
+
+ The relationship is defined using the SQLAlchemy function
+ :func:`~sqlalchemy.orm.relationship`. Once created, SQLAlchemy
+ inspects the arguments and underlying mappings involved
+ in order to classify the relationship as one of three types:
+ :term:`one to many`, :term:`many to one`, or :term:`many to many`.
+ With this classification, the relationship construct
+ handles the task of persisting the appropriate linkages
+ in the database in response to in-memory object associations,
+ as well as the job of loading object references and collections
+ into memory based on the current linkages in the
+ database.
+
+ .. seealso::
+
+ :ref:`relationship_config_toplevel`
+
+ association relationship
+ A two-tiered :term:`relationship` which links two tables
+ together using an association table in the middle. The
+ association relationship differs from a :term:`many to many`
+ relationship in that the many-to-many table is mapped
+ by a full class, rather than invisibly handled by the
+ :func:`sqlalchemy.orm.relationship` construct as in the case
+ with many-to-many, so that additional attributes are
+ explicitly available.
+
+ For example, if we wanted to associate employees with
+ projects, also storing the specific role for that employee
+ with the project, the relational schema might look like:
+
+ .. sourcecode:: sql
+
+ CREATE TABLE employee (
+ id INTEGER PRIMARY KEY,
+ name VARCHAR(30)
+ )
+
+ CREATE TABLE project (
+ id INTEGER PRIMARY KEY,
+ name VARCHAR(30)
+ )
+
+ CREATE TABLE employee_project (
+ employee_id INTEGER PRIMARY KEY,
+ project_id INTEGER PRIMARY KEY,
+ role_name VARCHAR(30),
+ FOREIGN KEY employee_id REFERENCES employee(id),
+ FOREIGN KEY project_id REFERENCES project(id)
+ )
+
+ A SQLAlchemy declarative mapping for the above might look like::
+
+ class Employee(Base):
+ __tablename__ = 'employee'
+
+ id = Column(Integer, primary_key)
+ name = Column(String(30))
+
+
+ class Project(Base):
+ __tablename__ = 'project'
+
+ id = Column(Integer, primary_key)
+ name = Column(String(30))
+
+
+ class EmployeeProject(Base):
+ __tablename__ = 'employee_project'
+
+ employee_id = Column(Integer, ForeignKey('employee.id'), primary_key=True)
+ project_id = Column(Integer, ForeignKey('project.id'), primary_key=True)
+ role_name = Column(String(30))
+
+ project = relationship("Project", backref="project_employees")
+ employee = relationship("Employee", backref="employee_projects")
+
+
+ Employees can be added to a project given a role name::
+
+ proj = Project(name="Client A")
+
+ emp1 = Employee(name="emp1")
+ emp2 = Employee(name="emp2")
+
+ proj.project_employees.extend([
+ EmployeeProject(employee=emp1, role="tech lead"),
+ EmployeeProject(employee=emp2, role="account executive")
+ ])
+
+ .. seealso::
+
+ :term:`many to many`
+
+ constraint
+ constraints
+ constrained
+ Rules established within a relational database that ensure
+ the validity and consistency of data. Common forms
+ of constraint include :term:`primary key constraint`,
+ :term:`foreign key constraint`, and :term:`check constraint`.
+
+ candidate key
+
+ A :term:`relational algebra` term referring to an attribute or set
+ of attributes that form a uniquely identifying key for a
+ row. A row may have more than one candidate key, each of which
+ is suitable for use as the primary key of that row.
+ The primary key of a table is always a candidate key.
+
+ .. seealso::
+
+ :term:`primary key`
+
+ http://en.wikipedia.org/wiki/Candidate_key
+
+ primary key
+ primary key constraint
+
+ A :term:`constraint` that uniquely defines the characteristics
+ of each :term:`row`. The primary key has to consist of
+ characteristics that cannot be duplicated by any other row.
+ The primary key may consist of a single attribute or
+ multiple attributes in combination.
+ (via Wikipedia)
+
+ The primary key of a table is typically, though not always,
+ defined within the ``CREATE TABLE`` :term:`DDL`:
+
+ .. sourcecode:: sql
+
+ CREATE TABLE employee (
+ emp_id INTEGER,
+ emp_name VARCHAR(30),
+ dep_id INTEGER,
+ PRIMARY KEY (emp_id)
+ )
+
+ .. seealso::
+
+ http://en.wikipedia.org/wiki/Primary_Key
+
+ foreign key constraint
+ A referential constraint between two tables. A foreign key is a field or set of fields in a
+ relational table that matches a :term:`candidate key` of another table.
+ The foreign key can be used to cross-reference tables.
+ (via Wikipedia)
+
+ A foreign key constraint can be added to a table in standard
+ SQL using :term:`DDL` like the following:
+
+ .. sourcecode:: sql
+
+ ALTER TABLE employee ADD CONSTRAINT dep_id_fk
+ FOREIGN KEY (employee) REFERENCES department (dep_id)
+
+ .. seealso::
+
+ http://en.wikipedia.org/wiki/Foreign_key_constraint
+
+ check constraint
+
+ A check constraint is a
+ condition that defines valid data when adding or updating an
+ entry in a table of a relational database. A check constraint
+ is applied to each row in the table.
+
+ (via Wikipedia)
+
+ A check constraint can be added to a table in standard
+ SQL using :term:`DDL` like the following:
+
+ .. sourcecode:: sql
+
+ ALTER TABLE distributors ADD CONSTRAINT zipchk CHECK (char_length(zipcode) = 5);
+
+ .. seealso::
+
+ http://en.wikipedia.org/wiki/Check_constraint
+
+ unique constraint
+ unique key index
+ A unique key index can uniquely identify each row of data
+ values in a database table. A unique key index comprises a
+ single column or a set of columns in a single database table.
+ No two distinct rows or data records in a database table can
+ have the same data value (or combination of data values) in
+ those unique key index columns if NULL values are not used.
+ Depending on its design, a database table may have many unique
+ key indexes but at most one primary key index.
+
+ (via Wikipedia)
+
+ .. seealso::
+
+ http://en.wikipedia.org/wiki/Unique_key#Defining_unique_keys
user-defined Python classes with database tables, and instances of those
classes (objects) with rows in their corresponding tables. It includes a
system that transparently synchronizes all changes in state between objects
-and their related rows, called a `unit of work
-<http://martinfowler.com/eaaCatalog/unitOfWork.html>`_, as well as a system
+and their related rows, called a :term:`unit of work`, as well as a system
for expressing database queries in terms of the user defined classes and their
defined relationships between each other.
While there is overlap among the usage patterns of the ORM and the Expression
Language, the similarities are more superficial than they may at first appear.
One approaches the structure and content of data from the perspective of a
-user-defined `domain model
-<http://en.wikipedia.org/wiki/Domain_model>`_ which is transparently
+user-defined :term:`domain model` which is transparently
persisted and refreshed from its underlying storage model. The other
approaches it from the perspective of literal schema and SQL expression
representations which are explicitly composed into messages consumed
>>> ed_user is our_user
True
-The ORM concept at work here is known as an `identity map <http://martinfowler.com/eaaCatalog/identityMap.html>`_
+The ORM concept at work here is known as an :term:`identity map`
and ensures that
all operations upon a particular row within a
:class:`~sqlalchemy.orm.session.Session` operate upon the same set of data.
Common Filter Operators
-----------------------
-Here's a rundown of some of the most common operators used in :func:`~sqlalchemy.orm.query.Query.filter`:
+Here's a rundown of some of the most common operators used in
+:func:`~sqlalchemy.orm.query.Query.filter`:
* equals::
query.filter(User.name.in_(['ed', 'wendy', 'jack']))
# works with query objects too:
-
- query.filter(User.name.in_(session.query(User.name).filter(User.name.like('%ed%'))))
+ query.filter(User.name.in_(
+ session.query(User.name).filter(User.name.like('%ed%'))
+ ))
* NOT IN::
* IS NULL::
- filter(User.name == None)
+ query.filter(User.name == None)
* IS NOT NULL::
- filter(User.name != None)
+ query.filter(User.name != None)
* AND::
+ # use and_()
from sqlalchemy import and_
- filter(and_(User.name == 'ed', User.fullname == 'Ed Jones'))
+ query.filter(and_(User.name == 'ed', User.fullname == 'Ed Jones'))
+
+ # or send multiple expressions to .filter()
+ query.filter(User.name == 'ed', User.fullname == 'Ed Jones')
- # or call filter()/filter_by() multiple times
- filter(User.name == 'ed').filter(User.fullname == 'Ed Jones')
+ # or chain multiple filter()/filter_by() calls
+ query.filter(User.name == 'ed').filter(User.fullname == 'Ed Jones')
* OR::
from sqlalchemy import or_
- filter(or_(User.name == 'ed', User.name == 'wendy'))
+ query.filter(or_(User.name == 'ed', User.name == 'wendy'))
* match::
Returning Lists and Scalars
---------------------------
-The :meth:`~sqlalchemy.orm.query.Query.all()`,
-:meth:`~sqlalchemy.orm.query.Query.one()`, and
-:meth:`~sqlalchemy.orm.query.Query.first()` methods of
-:class:`~sqlalchemy.orm.query.Query` immediately issue SQL and return a
-non-iterator value. :meth:`~sqlalchemy.orm.query.Query.all()` returns a list:
-
-.. sourcecode:: python+sql
-
- >>> query = session.query(User).filter(User.name.like('%ed')).order_by(User.id)
- {sql}>>> query.all() #doctest: +NORMALIZE_WHITESPACE
- SELECT users.id AS users_id,
- users.name AS users_name,
- users.fullname AS users_fullname,
- users.password AS users_password
- FROM users
- WHERE users.name LIKE ? ORDER BY users.id
- ('%ed',)
- {stop}[<User(name='ed', fullname='Ed Jones', password='f8s7ccs')>, <User(name='fred', fullname='Fred Flinstone', password='blah')>]
-
-:meth:`~sqlalchemy.orm.query.Query.first()` applies a limit of one and returns
-the first result as a scalar:
-
-.. sourcecode:: python+sql
-
- {sql}>>> query.first() #doctest: +NORMALIZE_WHITESPACE
- SELECT users.id AS users_id,
- users.name AS users_name,
- users.fullname AS users_fullname,
- users.password AS users_password
- FROM users
- WHERE users.name LIKE ? ORDER BY users.id
- LIMIT ? OFFSET ?
- ('%ed', 1, 0)
- {stop}<User(name='ed', fullname='Ed Jones', password='f8s7ccs')>
-
-:meth:`~sqlalchemy.orm.query.Query.one()`, fully fetches all rows, and if not
-exactly one object identity or composite row is present in the result, raises
-an error:
-
-.. sourcecode:: python+sql
-
- {sql}>>> from sqlalchemy.orm.exc import MultipleResultsFound
- >>> try: #doctest: +NORMALIZE_WHITESPACE
- ... user = query.one()
- ... except MultipleResultsFound, e:
- ... print e
- SELECT users.id AS users_id,
- users.name AS users_name,
- users.fullname AS users_fullname,
- users.password AS users_password
- FROM users
- WHERE users.name LIKE ? ORDER BY users.id
- ('%ed',)
- {stop}Multiple rows were found for one()
-
-.. sourcecode:: python+sql
-
- {sql}>>> from sqlalchemy.orm.exc import NoResultFound
- >>> try: #doctest: +NORMALIZE_WHITESPACE
- ... user = query.filter(User.id == 99).one()
- ... except NoResultFound, e:
- ... print e
- SELECT users.id AS users_id,
- users.name AS users_name,
- users.fullname AS users_fullname,
- users.password AS users_password
- FROM users
- WHERE users.name LIKE ? AND users.id = ? ORDER BY users.id
- ('%ed', 99)
- {stop}No row was found for one()
+A number of methods on :class:`.Query`
+immediately issue SQL and return a value containing loaded
+database results. Here's a brief tour:
+
+* :meth:`~.Query.all()` returns a list:
+
+ .. sourcecode:: python+sql
+
+ >>> query = session.query(User).filter(User.name.like('%ed')).order_by(User.id)
+ {sql}>>> query.all() #doctest: +NORMALIZE_WHITESPACE
+ SELECT users.id AS users_id,
+ users.name AS users_name,
+ users.fullname AS users_fullname,
+ users.password AS users_password
+ FROM users
+ WHERE users.name LIKE ? ORDER BY users.id
+ ('%ed',)
+ {stop}[<User(name='ed', fullname='Ed Jones', password='f8s7ccs')>,
+ <User(name='fred', fullname='Fred Flinstone', password='blah')>]
+
+* :meth:`~.Query.first()` applies a limit of one and returns
+ the first result as a scalar:
+
+ .. sourcecode:: python+sql
+
+ {sql}>>> query.first() #doctest: +NORMALIZE_WHITESPACE
+ SELECT users.id AS users_id,
+ users.name AS users_name,
+ users.fullname AS users_fullname,
+ users.password AS users_password
+ FROM users
+ WHERE users.name LIKE ? ORDER BY users.id
+ LIMIT ? OFFSET ?
+ ('%ed', 1, 0)
+ {stop}<User(name='ed', fullname='Ed Jones', password='f8s7ccs')>
+
+* :meth:`~.Query.one()`, fully fetches all rows, and if not
+ exactly one object identity or composite row is present in the result, raises
+ an error. With multiple rows found:
+
+ .. sourcecode:: python+sql
+
+ {sql}>>> from sqlalchemy.orm.exc import MultipleResultsFound
+ >>> try: #doctest: +NORMALIZE_WHITESPACE
+ ... user = query.one()
+ ... except MultipleResultsFound, e:
+ ... print e
+ SELECT users.id AS users_id,
+ users.name AS users_name,
+ users.fullname AS users_fullname,
+ users.password AS users_password
+ FROM users
+ WHERE users.name LIKE ? ORDER BY users.id
+ ('%ed',)
+ {stop}Multiple rows were found for one()
+
+ With no rows found:
+
+ .. sourcecode:: python+sql
+
+ {sql}>>> from sqlalchemy.orm.exc import NoResultFound
+ >>> try: #doctest: +NORMALIZE_WHITESPACE
+ ... user = query.filter(User.id == 99).one()
+ ... except NoResultFound, e:
+ ... print e
+ SELECT users.id AS users_id,
+ users.name AS users_name,
+ users.fullname AS users_fullname,
+ users.password AS users_password
+ FROM users
+ WHERE users.name LIKE ? AND users.id = ? ORDER BY users.id
+ ('%ed', 99)
+ {stop}No row was found for one()
+
+ The :meth:`~.Query.one` method is great for systems that expect to handle
+ "no items found" versus "multiple items found" differently; such as a RESTful
+ web service, which may want to raise a "404 not found" when no results are found,
+ but raise an application error when multiple results are found.
+
+* :meth:`~.Query.scalar` invokes the :meth:`~.Query.one` method, and upon
+ success returns the first column of the row:
+
+ .. sourcecode:: python+sql
+
+ >>> query = session.query(User.id).filter(User.name.like('%ed')).\
+ ... order_by(User.id)
+ {sql}>>> query.scalar() #doctest: +NORMALIZE_WHITESPACE
+ SELECT users.id AS users_id
+ FROM users
+ WHERE users.name LIKE ? ORDER BY users.id
+ LIMIT ? OFFSET ?
+ ('%ed', 1, 0)
+ {stop}7
.. _orm_tutorial_literal_sql:
The above class introduces the :class:`.ForeignKey` construct, which is a
directive applied to :class:`.Column` that indicates that values in this
-column should be **constrained** to be values present in the named remote
+column should be :term:`constrained` to be values present in the named remote
column. This is a core feature of relational databases, and is the "glue" that
transforms an otherwise unconnected collection of tables to have rich
overlapping relationships. The :class:`.ForeignKey` above expresses that
to the ``User`` class, using the attribute ``Address.user``.
:func:`.relationship` uses the foreign key
relationships between the two tables to determine the nature of
-this linkage, determining that ``Address.user`` will be **many-to-one**.
+this linkage, determining that ``Address.user`` will be :term:`many to one`.
A subdirective of :func:`.relationship` called :func:`.backref` is
placed inside of :func:`.relationship`, providing details about
the relationship as expressed in reverse, that of a collection of ``Address``
objects on ``User`` referenced by ``User.addresses``. The reverse
-side of a many-to-one relationship is always **one-to-many**.
+side of a many-to-one relationship is always :term:`one to many`.
A full catalog of available :func:`.relationship` configurations
is at :ref:`relationship_patterns`.
The two complementing relationships ``Address.user`` and ``User.addresses``
-are referred to as a **bidirectional relationship**, and is a key
+are referred to as a :term:`bidirectional relationship`, and is a key
feature of the SQLAlchemy ORM. The section :ref:`relationships_backref`
discusses the "backref" feature in detail.
{stop}[<Address(email_address='jack@google.com')>, <Address(email_address='j25@yahoo.com')>]
When we accessed the ``addresses`` collection, SQL was suddenly issued. This
-is an example of a **lazy loading relationship**. The ``addresses`` collection
+is an example of a :term:`lazy loading` relationship. The ``addresses`` collection
is now loaded and behaves just like an ordinary list. We'll cover ways
to optimize the loading of this collection in a bit.
Eager Loading
=============
-Recall earlier that we illustrated a **lazy loading** operation, when
+Recall earlier that we illustrated a :term:`lazy loading` operation, when
we accessed the ``User.addresses`` collection of a ``User`` and SQL
was emitted. If you want to reduce the number of queries (dramatically, in many cases),
-we can apply an **eager load** to the query operation. SQLAlchemy
+we can apply an :term:`eager load` to the query operation. SQLAlchemy
offers three types of eager loading, two of which are automatic, and a third
which involves custom criterion. All three are usually invoked via functions known
-as **query options** which give additional instructions to the :class:`.Query` on how
+as :term:`query options` which give additional instructions to the :class:`.Query` on how
we would like various attributes to be loaded, via the :meth:`.Query.options` method.
Subquery Load