Skip to content

Commit 7d65e2d

Browse files
authored
Merge pull request pallets-eco#415 from justanr/ISSUE-396-query_class-documentation
Provide documentation for use of query_class
2 parents eade982 + a61cf1a commit 7d65e2d

File tree

2 files changed

+124
-0
lines changed

2 files changed

+124
-0
lines changed

docs/contents.rst.inc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ Flask-SQLAlchemy with Flask.
1414
queries
1515
binds
1616
signals
17+
customizing
1718
1819
API Reference
1920
-------------

docs/customizing.rst

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
.. _customizing:
2+
3+
.. currentmodule:: flask_sqlalchemy
4+
5+
Customizing
6+
===========
7+
8+
Flask-SQLAlchemy defines sensible defaults. However, sometimes customization is
9+
needed. Two major pieces to customize are the Model base class and the default
10+
Query class.
11+
12+
Both of these customizations are applied at the creation of the :class:`SQLAlchemy`
13+
object and extend to all models derived from its ``Model`` class.
14+
15+
Model Class
16+
-----------
17+
18+
Flask-SQLAlchemy allows defining a custom declarative base, just like SQLAlchemy,
19+
that all model classes should extend from. For example, if all models should have
20+
a custom ``__repr__`` method::
21+
22+
from flask_sqlalchemy import Model # this is the default declarative base
23+
from flask_sqlalchemy import SQLAlchemy
24+
25+
class ReprBase(Model):
26+
def __repr__(self):
27+
return "<{0} id: {1}>".format(self.__class__.__name__, self.id)
28+
29+
db = SQLAlchemy(model_class=ReprBase)
30+
31+
class MyModel(db.Model):
32+
...
33+
34+
.. note::
35+
36+
While not strictly necessary to inherit from :class:`flask_sqlalchemy.Model`
37+
it is encouraged as future changes may cause incompatibility.
38+
39+
.. note::
40+
41+
If behavior is needed in only some models, not all, a better strategy
42+
is to use a Mixin, as exampled below.
43+
44+
While this particular example is more useful for debugging, it is possible to
45+
provide many augmentations to models that would otherwise be achieved with
46+
mixins instead. The above example is equivalent to the following::
47+
48+
class ReprBase(object):
49+
def __repr__(self):
50+
return "<{0} id: {1}>".format(self.__class__.__name__, self.id)
51+
52+
db = SQLAlchemy()
53+
54+
class MyModel(db.Model, ReprBase):
55+
...
56+
57+
It also possible to provide default columns and properties to all models as well::
58+
59+
from flask_sqlalchemy import Model, SQLAlchemy
60+
from sqlalchemy import Column, DateTime
61+
from datetime import datetime
62+
63+
class TimestampedModel(Model):
64+
created_at = Column(DateTime, default=datetime.utcnow)
65+
66+
db = SQLAlchemy(model_class=TimestampedModel)
67+
68+
class MyModel(db.Model):
69+
...
70+
71+
All model classes extending from ``db.Model`` will now inherit a
72+
``created_at`` column.
73+
74+
Query Class
75+
-----------
76+
77+
It is also possible to customize what is availble for use on the
78+
special ``query`` property of models. For example, providing a
79+
``get_or`` method::
80+
81+
from flask_sqlalchemy import BaseQuery, SQLAlchemy
82+
83+
class GetOrQuery(BaseQuery):
84+
def get_or(self, ident, default=None):
85+
return self.get(ident) or default
86+
87+
db = SQLAlchemy(query_class=GetOrQuery)
88+
89+
And now all queries executed from the special ``query`` property
90+
on Flask-SQLAlchemy models can use the ``get_or`` method as part
91+
of their queries. All relationships defined with
92+
``db.relationship`` (but not :func:`sqlalchemy.relationship`)
93+
will also be provided with this functionality.
94+
95+
.. warning::
96+
97+
Unlike a custom ``Model`` base class, it is required
98+
to either inherit from either :class:`flask_sqlalchemy.BaseQuery`
99+
or :func:`sqlalchemy.orm.Query` in order to define a custom
100+
query class.
101+
102+
It also possible to define a custom query class for individual
103+
relationships as well, by providing the ``query_class`` keyword
104+
in the definition. This works with both ``db.relationship``
105+
and ``sqlalchemy.relationship``::
106+
107+
class MyModel(db.Model):
108+
cousin = db.relationship('OtherModel', query_class=GetOrQuery)
109+
110+
.. note::
111+
112+
If a query class is defined on a relationship, it will take
113+
precedence over the query class attached to its corresponding
114+
model.
115+
116+
It is also possible to define a specific query class for individual models
117+
by overriding the ``query_class`` class attribute on the model::
118+
119+
class MyModel(db.Model):
120+
query_class = GetOrQuery
121+
122+
In this case, the ``get_or`` method will be only availble on queries
123+
orginating from ``MyModel.query``.

0 commit comments

Comments
 (0)