Skip to content

Commit d8c31ca

Browse files
committed
Document refactor to emphasize 2.x, fix for bind key and metadata for 2.x
1 parent b052dd6 commit d8c31ca

File tree

8 files changed

+283
-129
lines changed

8 files changed

+283
-129
lines changed

docs/config.rst

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -151,31 +151,6 @@ only need to use :data:`SQLALCHEMY_DATABASE_URI` and :data:`SQLALCHEMY_ENGINE_OP
151151
in that engine's options.
152152

153153

154-
Using custom MetaData and naming conventions
155-
--------------------------------------------
156-
157-
You can optionally construct the :class:`.SQLAlchemy` object with a custom
158-
:class:`~sqlalchemy.schema.MetaData` object. This allows you to specify a custom
159-
constraint `naming convention`_. This makes constraint names consistent and predictable,
160-
useful when using migrations, as described by `Alembic`_.
161-
162-
.. code-block:: python
163-
164-
from sqlalchemy import MetaData
165-
from flask_sqlalchemy import SQLAlchemy
166-
167-
db = SQLAlchemy(metadata=MetaData(naming_convention={
168-
"ix": 'ix_%(column_0_label)s',
169-
"uq": "uq_%(table_name)s_%(column_0_name)s",
170-
"ck": "ck_%(table_name)s_%(constraint_name)s",
171-
"fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s",
172-
"pk": "pk_%(table_name)s"
173-
}))
174-
175-
.. _naming convention: https://docs.sqlalchemy.org/core/constraints.html#constraint-naming-conventions
176-
.. _Alembic: https://alembic.sqlalchemy.org/en/latest/naming.html
177-
178-
179154
Timeouts
180155
--------
181156

docs/legacy-quickstart.rst

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
2+
:orphan:
3+
4+
Legacy Quickstart
5+
======================
6+
7+
.. warning::
8+
This guide shows you how to initialize the extension and define models
9+
when using the SQLAlchemy 1.x style of ORM model classes. We encourage you to
10+
upgrade to `SQLAlchemy 2.x`_ to take advantage of the new typed model classes.
11+
12+
.. _SQLAlchemy 2.x: https://docs.sqlalchemy.org/en/20/orm/quickstart.html
13+
14+
Initialize the Extension
15+
------------------------
16+
17+
First create the ``db`` object using the ``SQLAlchemy`` constructor.
18+
19+
When using the SQLAlchemy 1.x API, you do not need to pass any arguments to the ``SQLAlchemy`` constructor.
20+
A declarative base class will be created behind the scenes for you.
21+
22+
.. code-block:: python
23+
24+
from flask import Flask
25+
from flask_sqlalchemy import SQLAlchemy
26+
from sqlalchemy.orm import DeclarativeBase
27+
28+
db = SQLAlchemy()
29+
30+
31+
Using custom MetaData and naming conventions
32+
--------------------------------------------
33+
34+
You can optionally construct the :class:`.SQLAlchemy` object with a custom
35+
:class:`~sqlalchemy.schema.MetaData` object. This allows you to specify a custom
36+
constraint `naming convention`_. This makes constraint names consistent and predictable,
37+
useful when using migrations, as described by `Alembic`_.
38+
39+
.. code-block:: python
40+
41+
from sqlalchemy import MetaData
42+
from flask_sqlalchemy import SQLAlchemy
43+
44+
db = SQLAlchemy(metadata=MetaData(naming_convention={
45+
"ix": 'ix_%(column_0_label)s',
46+
"uq": "uq_%(table_name)s_%(column_0_name)s",
47+
"ck": "ck_%(table_name)s_%(constraint_name)s",
48+
"fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s",
49+
"pk": "pk_%(table_name)s"
50+
}))
51+
52+
.. _naming convention: https://docs.sqlalchemy.org/core/constraints.html#constraint-naming-conventions
53+
.. _Alembic: https://alembic.sqlalchemy.org/en/latest/naming.html
54+
55+
56+
57+
Define Models
58+
-------------
59+
60+
Subclass ``db.Model`` to define a model class. This is a SQLAlchemy declarative base
61+
class, it will take ``Column`` attributes and create a table.
62+
63+
.. code-block:: python
64+
65+
class User(db.Model):
66+
id = db.Column(db.Integer, primary_key=True)
67+
username = db.Column(db.String, unique=True, nullable=False)
68+
email = db.Column(db.String)
69+
70+
For convenience, the extension object provides access to names in the ``sqlalchemy`` and
71+
``sqlalchemy.orm`` modules. So you can use ``db.Column`` instead of importing and using
72+
``sqlalchemy.Column``, although the two are equivalent.
73+
74+
Unlike plain SQLAlchemy, Flask-SQLAlchemy's model will automatically generate a table name
75+
if ``__tablename__`` is not set and a primary key column is defined.
76+
The table name ``"user"`` will automatically be assigned to the model's table.
77+
78+
79+
Create the Tables
80+
-----------------
81+
82+
Defining a model does not create it in the database. Use :meth:`~.SQLAlchemy.create_all`
83+
to create the models and tables after defining them. If you define models in submodules,
84+
you must import them so that SQLAlchemy knows about them before calling ``create_all``.
85+
86+
.. code-block:: python
87+
88+
with app.app_context():
89+
db.create_all()
90+
91+
Querying the Data
92+
-----------------
93+
94+
You can query the data the same way regardless of SQLAlchemy version.
95+
See :doc:`queries` for more information about queries.

docs/models.rst

Lines changed: 68 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,35 +4,82 @@ Models and Tables
44
Use the ``db.Model`` class to define models, or the ``db.Table`` class to create tables.
55
Both handle Flask-SQLAlchemy's bind keys to associate with a specific engine.
66

7+
Initializing the Base Class
8+
---------------------------
79

8-
Defining Models
9-
---------------
10+
``SQLAlchemy`` 2.x offers several possible base classes for your models:
11+
`DeclarativeBase`_ or `DeclarativeBaseNoMeta`_.
1012

11-
See SQLAlchemy's `declarative documentation`_ for full information about defining model
12-
classes declaratively.
13+
Create a subclass of one of those classes:
1314

14-
.. _declarative documentation: https://docs.sqlalchemy.org/orm/declarative_tables.html
15+
.. code-block:: python
1516
16-
Subclass ``db.Model`` to create a model class. This is a SQLAlchemy declarative base
17-
class, it will take ``Column`` attributes and create a table. Unlike plain SQLAlchemy,
18-
Flask-SQLAlchemy's model will automatically generate a table name if ``__tablename__``
19-
is not set and a primary key column is defined.
17+
from flask import Flask
18+
from flask_sqlalchemy import SQLAlchemy
19+
from sqlalchemy.orm import DeclarativeBase
20+
21+
class Base(DeclarativeBase):
22+
pass
23+
24+
.. _DeclarativeBase: https://docs.sqlalchemy.org/en/20/orm/mapping_api.html#sqlalchemy.orm.DeclarativeBase
25+
.. _DeclarativeBaseNoMeta: https://docs.sqlalchemy.org/en/20/orm/mapping_api.html#sqlalchemy.orm.DeclarativeBaseNoMeta
26+
27+
If desired, you can enable `SQLAlchemy's native support for data classes`_
28+
by adding `MappedAsDataclass` as an additional parent class.
2029

2130
.. code-block:: python
2231
23-
import sqlalchemy as sa
32+
from sqlalchemy.orm import DeclarativeBase, MappedAsDataclass
2433
25-
class User(db.Model):
26-
id = sa.Column(sa.Integer, primary_key=True)
27-
type = sa.Column(sa.String)
34+
class Base(DeclarativeBase, MappedAsDataclass):
35+
pass
36+
37+
.. _SQLAlchemy's native support for data classes: https://docs.sqlalchemy.org/en/20/changelog/whatsnew_20.html#native-support-for-dataclasses-mapped-as-orm-models
38+
39+
40+
You can optionally construct the :class:`.SQLAlchemy` object with a custom
41+
:class:`~sqlalchemy.schema.MetaData` object. This allows you to specify a custom
42+
constraint `naming convention`_. This makes constraint names consistent and predictable,
43+
useful when using migrations, as described by `Alembic`_.
44+
45+
.. code-block:: python
46+
47+
from sqlalchemy import MetaData
2848
29-
For convenience, the extension object provides access to names in the ``sqlalchemy`` and
30-
``sqlalchemy.orm`` modules. So you can use ``db.Column`` instead of importing and using
31-
``sqlalchemy.Column``, although the two are equivalent.
49+
class Base(DeclarativeBase):
50+
metadata = MetaData(naming_convention={
51+
"ix": 'ix_%(column_0_label)s',
52+
"uq": "uq_%(table_name)s_%(column_0_name)s",
53+
"ck": "ck_%(table_name)s_%(constraint_name)s",
54+
"fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s",
55+
"pk": "pk_%(table_name)s"
56+
})
3257
33-
It's also possible to use the SQLAlchemy 2.x style of defining models,
34-
as long as you initialized the extension with an appropriate 2.x model base class
35-
(as described in the quickstart).
58+
.. _naming convention: https://docs.sqlalchemy.org/core/constraints.html#constraint-naming-conventions
59+
.. _Alembic: https://alembic.sqlalchemy.org/en/latest/naming.html
60+
61+
62+
Initialize the Extension
63+
------------------------
64+
65+
Once you've defined a base class, create the ``db`` object using the ``SQLAlchemy`` constructor.
66+
67+
.. code-block:: python
68+
69+
db = SQLAlchemy(model_class=Base)
70+
71+
72+
Defining Models
73+
---------------
74+
75+
See SQLAlchemy's `declarative documentation`_ for full information about defining model
76+
classes declaratively.
77+
78+
.. _declarative documentation: https://docs.sqlalchemy.org/en/20/orm/declarative_tables.html
79+
80+
Subclass ``db.Model`` to create a model class. Unlike plain SQLAlchemy,
81+
Flask-SQLAlchemy's model will automatically generate a table name if ``__tablename__``
82+
is not set and a primary key column is defined.
3683

3784
.. code-block:: python
3885
@@ -43,6 +90,7 @@ as long as you initialized the extension with an appropriate 2.x model base clas
4390
username: Mapped[str] = mapped_column(db.String, unique=True, nullable=False)
4491
email: Mapped[str] = mapped_column(db.String)
4592
93+
4694
Defining a model does not create it in the database. Use :meth:`~.SQLAlchemy.create_all`
4795
to create the models and tables after defining them. If you define models in submodules,
4896
you must import them so that SQLAlchemy knows about them before calling ``create_all``.
@@ -59,7 +107,7 @@ Defining Tables
59107
See SQLAlchemy's `table documentation`_ for full information about defining table
60108
objects.
61109

62-
.. _table documentation: https://docs.sqlalchemy.org/core/metadata.html
110+
.. _table documentation: https://docs.sqlalchemy.org/en/20/core/metadata.html
63111

64112
Create instances of ``db.Table`` to define tables. The class takes a table name, then
65113
any columns and other table parts such as columns and constraints. Unlike plain

docs/quickstart.rst

Lines changed: 12 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,14 @@ Flask-SQLAlchemy is a wrapper around SQLAlchemy. You should follow the
2121
`SQLAlchemy Tutorial`_ to learn about how to use it, and consult its documentation
2222
for detailed information about its features. These docs show how to set up
2323
Flask-SQLAlchemy itself, not how to use SQLAlchemy. Flask-SQLAlchemy sets up the
24-
engine, declarative model class, and scoped session automatically, so you can skip those
24+
engine and scoped session automatically, so you can skip those
2525
parts of the SQLAlchemy tutorial.
2626

27-
.. _SQLAlchemy Tutorial: https://docs.sqlalchemy.org/tutorial/index.html
27+
.. _SQLAlchemy Tutorial: https://docs.sqlalchemy.org/en/20/tutorial/index.html
2828

29+
This guide assumes you are using SQLAlchemy 2.x, which has a new API for defining models
30+
and better support for Python type hints and data classes. If you are using SQLAlchemy 1.x,
31+
see :doc:`legacy-quickstart`.
2932

3033
Installation
3134
------------
@@ -44,30 +47,8 @@ Initialize the Extension
4447
------------------------
4548

4649
First create the ``db`` object using the ``SQLAlchemy`` constructor.
47-
The initialization step depends on which version of ``SQLAlchemy`` you're using.
48-
This extension supports both SQLAlchemy 1 and 2, but defaults to SQLAlchemy 1.
4950

50-
.. _sqlalchemy1-initialization:
51-
52-
Using the SQLAlchemy 1 API
53-
^^^^^^^^^^^^^^^^^^^^^^^^^^
54-
55-
To use the SQLAlchemy 1.x API, you do not need to pass any arguments to the ``SQLAlchemy`` constructor.
56-
57-
.. code-block:: python
58-
59-
from flask import Flask
60-
from flask_sqlalchemy import SQLAlchemy
61-
from sqlalchemy.orm import DeclarativeBase
62-
63-
db = SQLAlchemy()
64-
65-
.. _sqlalchemy2-initialization:
66-
67-
Using the SQLAlchemy 2 API
68-
^^^^^^^^^^^^^^^^^^^^^^^^^^
69-
70-
To use the new SQLAlchemy 2.x API, pass a subclass of either `DeclarativeBase`_ or `DeclarativeBaseNoMeta`_
51+
Pass a subclass of either `DeclarativeBase`_ or `DeclarativeBaseNoMeta`_
7152
to the constructor.
7253

7354
.. code-block:: python
@@ -81,21 +62,11 @@ to the constructor.
8162
8263
db = SQLAlchemy(model_class=Base)
8364
84-
If desired, you can enable `SQLAlchemy's native support for data classes`_
85-
by adding `MappedAsDataclass` as an additional parent class.
8665
87-
.. code-block:: python
88-
89-
from sqlalchemy.orm import DeclarativeBase, MappedAsDataclass
90-
91-
class Base(DeclarativeBase, MappedAsDataclass):
92-
pass
93-
94-
db = SQLAlchemy(model_class=Base)
66+
Learn more about customizing the base model class in :doc:`models`.
9567

9668
.. _DeclarativeBase: https://docs.sqlalchemy.org/en/20/orm/mapping_api.html#sqlalchemy.orm.DeclarativeBase
9769
.. _DeclarativeBaseNoMeta: https://docs.sqlalchemy.org/en/20/orm/mapping_api.html#sqlalchemy.orm.DeclarativeBaseNoMeta
98-
.. _SQLAlchemy's native support for data classes: https://docs.sqlalchemy.org/en/20/changelog/whatsnew_20.html#native-support-for-dataclasses-mapped-as-orm-models
9970

10071
About the ``SQLAlchemy`` object
10172
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -134,34 +105,19 @@ keys are used.
134105
Define Models
135106
-------------
136107

137-
Subclass ``db.Model`` to define a model class. The ``db`` object makes the names in
138-
``sqlalchemy`` and ``sqlalchemy.orm`` available for convenience, such as ``db.Column``.
108+
Subclass ``db.Model`` to define a model class.
139109
The model will generate a table name by converting the ``CamelCase`` class name to
140110
``snake_case``.
141111

142-
This example uses the SQLAlchemy 1.x style of defining models:
143-
144-
.. code-block:: python
145-
146-
class User(db.Model):
147-
id = db.Column(db.Integer, primary_key=True)
148-
username = db.Column(db.String, unique=True, nullable=False)
149-
email = db.Column(db.String)
150-
151-
The table name ``"user"`` will automatically be assigned to the model's table.
152-
153-
It's also possible to use the SQLAlchemy 2.x style of defining models,
154-
as long as you initialized the extension with an appropriate 2.x model base class
155-
as described in :ref:`sqlalchemy2-initialization`.
156-
157112
.. code-block:: python
158113
114+
from sqlalchemy import Integer, String
159115
from sqlalchemy.orm import Mapped, mapped_column
160116
161117
class User(db.Model):
162-
id: Mapped[int] = mapped_column(db.Integer, primary_key=True)
163-
username: Mapped[str] = mapped_column(db.String, unique=True, nullable=False)
164-
email: Mapped[str] = mapped_column(db.String)
118+
id: Mapped[int] = mapped_column(Integer, primary_key=True)
119+
username: Mapped[str] = mapped_column(String, unique=True, nullable=False)
120+
email: Mapped[str] = mapped_column(String)
165121
166122
167123
See :doc:`models` for more information about defining and creating models and tables.

0 commit comments

Comments
 (0)