# Technical Documentation: pallets-eco/flask-sqlalchemy > ℹ️ **Provenance:** Hybrid Fusion: `pallets-eco/flask-sqlalchemy` (README + 9 In-Tree Chapters) · [CodeWiki Reference](https://codewiki.google/github.com/pallets-eco/flask-sqlalchemy) · Recency: Active (< 180 days) ## 1. Project Overview & Quickstart (pallets-eco/flask-sqlalchemy) # Flask-SQLAlchemy Flask-SQLAlchemy is an extension for [Flask][] that adds support for [SQLAlchemy][] to your application. It aims to simplify using SQLAlchemy with Flask by providing useful defaults and extra helpers that make it easier to accomplish common tasks. [Flask]: https://flask.palletsprojects.com [SQLAlchemy]: https://www.sqlalchemy.org ## Pallets Community Ecosystem > [!IMPORTANT]\ > This project is part of the Pallets Community Ecosystem. Pallets is the open > source organization that maintains Flask; Pallets-Eco enables community > maintenance of Flask extensions. If you are interested in helping maintain > this project, please reach out on [the Pallets Discord server][discord]. > > [discord]: https://discord.gg/pallets ## A Simple Example ```python from flask import Flask from flask_sqlalchemy import SQLAlchemy from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column app = Flask(__name__) app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///example.sqlite" class Base(DeclarativeBase): pass db = SQLAlchemy(app, model_class=Base) class User(db.Model): id: Mapped[int] = mapped_column(primary_key=True) username: Mapped[str] = mapped_column(unique=True) with app.app_context(): db.create_all() db.session.add(User(username="example")) db.session.commit() users = db.session.scalars(db.select(User)) ``` ## 2. In-Tree Documentation Chapters (pallets-eco/flask-sqlalchemy) ## File: README.md # Flask-SQLAlchemy Flask-SQLAlchemy is an extension for [Flask][] that adds support for [SQLAlchemy][] to your application. It aims to simplify using SQLAlchemy with Flask by providing useful defaults and extra helpers that make it easier to accomplish common tasks. [Flask]: https://flask.palletsprojects.com [SQLAlchemy]: https://www.sqlalchemy.org ## Pallets Community Ecosystem > [!IMPORTANT]\ > This project is part of the Pallets Community Ecosystem. Pallets is the open > source organization that maintains Flask; Pallets-Eco enables community > maintenance of Flask extensions. If you are interested in helping maintain > this project, please reach out on [the Pallets Discord server][discord]. > > [discord]: https://discord.gg/pallets ## A Simple Example ```python from flask import Flask from flask_sqlalchemy import SQLAlchemy from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column app = Flask(__name__) app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///example.sqlite" class Base(DeclarativeBase): pass db = SQLAlchemy(app, model_class=Base) class User(db.Model): id: Mapped[int] = mapped_column(primary_key=True) username: Mapped[str] = mapped_column(unique=True) with app.app_context(): db.create_all() db.session.add(User(username="example")) db.session.commit() users = db.session.scalars(db.select(User)) ``` --- ## File: docs/api.rst API === Extension --------- .. module:: flask_sqlalchemy .. autoclass:: SQLAlchemy :members: Model ----- .. module:: flask_sqlalchemy.model .. autoclass:: Model :members: .. attribute:: __bind_key__ Use this bind key to select a metadata and engine to associate with this model's table. Ignored if ``metadata`` or ``__table__`` is set. If not given, uses the default key, ``None``. .. attribute:: __tablename__ The name of the table in the database. This is required by SQLAlchemy; however, Flask-SQLAlchemy will set it automatically if a model has a primary key defined. If the ``__table__`` or ``__tablename__`` is set explicitly, that will be used instead. Metaclass mixins (SQLAlchemy 1.x) --------------------------------- If your code uses the SQLAlchemy 1.x API (the default for code that doesn't specify a ``model_class``), then these mixins are automatically applied to the ``Model`` class. .. autoclass:: DefaultMeta .. autoclass:: BindMetaMixin .. autoclass:: NameMetaMixin Session ------- .. module:: flask_sqlalchemy.session .. autoclass:: Session :members: Pagination ---------- .. module:: flask_sqlalchemy.pagination .. class:: Pagination A slice of the total items in a query obtained by applying an offset and limit to based on the current page and number of items per page. Don't create pagination objects manually. They are created by :meth:`.SQLAlchemy.paginate` and :meth:`.Query.paginate`. .. versionchanged:: 3.0 Iterating over a pagination object iterates over its items. .. versionchanged:: 3.0 Creating instances manually is not a public API. .. autoattribute:: page .. autoattribute:: per_page .. autoattribute:: items .. autoattribute:: total .. autoproperty:: first .. autoproperty:: last .. autoproperty:: pages .. autoproperty:: has_prev .. autoproperty:: prev_num .. automethod:: prev .. autoproperty:: has_next .. autoproperty:: next_num .. automethod:: next .. automethod:: iter_pages Query ----- .. module:: flask_sqlalchemy.query .. autoclass:: Query :members: Record Queries -------------- .. module:: flask_sqlalchemy.record_queries .. autofunction:: get_recorded_queries Track Modifications ------------------- .. module:: flask_sqlalchemy.track_modifications .. autodata:: models_committed :no-value: .. autodata:: before_models_committed :no-value: --- ## File: docs/binds.rst Multiple Databases with Binds ============================= SQLAlchemy can connect to more than one database at a time. It refers to different engines as "binds". Flask-SQLAlchemy simplifies how binds work by associating each engine with a short string, a "bind key", and then associating each model and table with a bind key. The session will choose what engine to use for a query based on the bind key of the thing being queried. If no bind key is given, the default engine is used. Configuring Binds ----------------- The default bind is still configured by setting :data:`.SQLALCHEMY_DATABASE_URI`, and :data:`.SQLALCHEMY_ENGINE_OPTIONS` for any engine options. Additional binds are given in :data:`.SQLALCHEMY_BINDS`, a dict mapping bind keys to engine URLs. To specify engine options for a bind, the value can be a dict of engine options with the ``"url"`` key, instead of only a URL string. .. code-block:: python SQLALCHEMY_DATABASE_URI = "postgresql:///main" SQLALCHEMY_BINDS = { "meta": "sqlite:////path/to/meta.db", "auth": { "url": "mysql://localhost/users", "pool_recycle": 3600, }, } Defining Models and Tables with Binds ------------------------------------- Flask-SQLAlchemy will create a metadata and engine for each configured bind. Models and tables with a bind key will be registered with the corresponding metadata, and the session will query them using the corresponding engine. To set the bind for a model, set the ``__bind_key__`` class attribute. Not setting a bind key is equivalent to setting it to ``None``, the default key. .. code-block:: python class User(db.Model): __bind_key__ = "auth" id = db.Column(db.Integer, primary_key=True) Models that inherit from this model will share the same bind key, or can override it. To set the bind for a table, pass the ``bind_key`` keyword argument. .. code-block:: python user_table = db.Table( "user", db.Column("id", db.Integer, primary_key=True), bind_key="auth", ) Ultimately, the session looks up the bind key on the metadata associated with the model or table. That association happens during creation. Therefore, changing the bind key after creating a model or table will have no effect. Accessing Metadata and Engines ------------------------------ You may need to inspect the metadata or engine for a bind. Note that you should execute queries through the session, not directly on the engine. The default engine is :attr:`.SQLAlchemy.engine`, and the default metadata is :attr:`.SQLAlchemy.metadata`. :attr:`.SQLAlchemy.engines` and :attr:`.SQLAlchemy.metadatas` are dicts mapping all bind keys. Creating and Dropping Tables ---------------------------- The :meth:`~.SQLAlchemy.create_all` and :meth:`~.SQLAlchemy.drop_all` methods operate on all binds by default. The ``bind_key`` argument to these methods can be a string or ``None`` to operate on a single bind, or a list of strings or ``None`` to operate on a subset of binds. Because these methods access the engines, they must be called inside an application context. .. code-block:: python # create tables for all binds db.create_all() # create tables for the default and "auth" binds db.create_all(bind_key=[None, "auth"]) # create tables for the "meta" bind db.create_all(bind_key="meta") # drop tables for the default bind db.drop_all(bind_key=None) --- ## File: docs/config.rst Configuration ============= Configuration Keys ------------------ Configuration is loaded from the Flask ``app.config`` when :meth:`.SQLAlchemy.init_app` is called. The configuration is not read again after that. Therefore, all configuration must happen before initializing the application. .. module:: flask_sqlalchemy.config .. data:: SQLALCHEMY_DATABASE_URI The database connection URI used for the default engine. It can be either a string or a SQLAlchemy ``URL`` instance. See below and :external:doc:`core/engines` for examples. At least one of this and :data:`SQLALCHEMY_BINDS` must be set. .. versionchanged:: 3.0 No longer defaults to an in-memory SQLite database if not set. .. data:: SQLALCHEMY_ENGINE_OPTIONS A dict of arguments to pass to :func:`sqlalchemy.create_engine` for the default engine. This takes precedence over the ``engine_options`` argument to :class:`.SQLAlchemy`, which can be used to set default options for all engines. .. versionchanged:: 3.0 Only applies to the default bind. .. versionadded:: 2.4 .. data:: SQLALCHEMY_BINDS A dict mapping bind keys to engine options. The value can be a string or a SQLAlchemy ``URL`` instance. Or it can be a dict of arguments, including the ``url`` key, that will be passed to :func:`sqlalchemy.create_engine`. The ``None`` key can be used to configure the default bind, but :data:`SQLALCHEMY_ENGINE_OPTIONS` and :data:`SQLALCHEMY_DATABASE_URI` take precedence. At least one of this and :data:`SQLALCHEMY_DATABASE_URI` must be set. .. versionadded:: 0.12 .. data:: SQLALCHEMY_ECHO The default value for ``echo`` and ``echo_pool`` for every engine. This is useful to quickly debug the connections and queries issued from SQLAlchemy. .. versionchanged:: 3.0 Sets ``echo_pool`` in addition to ``echo``. .. data:: SQLALCHEMY_RECORD_QUERIES If enabled, information about each query during a request will be recorded. Use :func:`.get_recorded_queries` to get a list of queries that were issued during the request. .. versionchanged:: 3.0 Not enabled automatically in debug or testing mode. .. data:: SQLALCHEMY_TRACK_MODIFICATIONS If enabled, all ``insert``, ``update``, and ``delete`` operations on models are recorded, then sent in :data:`.models_committed` and :data:`.before_models_committed` signals when ``session.commit()`` is called. This adds a significant amount of overhead to every session. Prefer using SQLAlchemy's :external:doc:`orm/events` directly for the exact information you need. .. versionchanged:: 3.0 Disabled by default. .. versionadded:: 2.0 .. versionchanged:: 3.1 Removed ``SQLALCHEMY_COMMIT_ON_TEARDOWN``. .. versionchanged:: 3.0 Removed ``SQLALCHEMY_NATIVE_UNICODE``, ``SQLALCHEMY_POOL_SIZE``, ``SQLALCHEMY_POOL_TIMEOUT``, ``SQLALCHEMY_POOL_RECYCLE``, and ``SQLALCHEMY_MAX_OVERFLOW``. Connection URL Format --------------------- See SQLAlchemy's documentation on :external:doc:`core/engines` for a complete description of syntax, dialects, and options. A basic database connection URL uses the following format. Username, password, host, and port are optional depending on the database type and configuration. .. code-block:: text dialect://username:password@host:port/database Here are some example connection strings: .. code-block:: text # SQLite, relative to Flask instance path sqlite:///project.db # PostgreSQL postgresql://scott:tiger@localhost/project # MySQL / MariaDB mysql://scott:tiger@localhost/project SQLite does not use a user or host, so its URLs always start with _three_ slashes instead of two. The ``dbname`` value is a file path. Absolute paths start with a _fourth_ slash (on Linux or Mac). Relative paths are relative to the Flask application's :attr:`~flask.Flask.instance_path`. Default Driver Options ---------------------- Some default options are set for SQLite and MySQL engines to make them more usable by default in web applications. SQLite relative file paths are relative to the Flask instance path instead of the current working directory. In-memory databases use a static pool and ``check_same_thread`` to work across requests. MySQL (and MariaDB) servers are configured to drop connections that have been idle for 8 hours, which can result in an error like ``2013: Lost connection to MySQL server during query``. A default ``pool_recycle`` value of 2 hours (7200 seconds) is used to recreate connections before that timeout. Engine Configuration Precedence ------------------------------- Because Flask-SQLAlchemy has support for multiple engines, there are rules for which config overrides other config. Most applications will only have a single database and only need to use :data:`SQLALCHEMY_DATABASE_URI` and :data:`SQLALCHEMY_ENGINE_OPTIONS`. - If the ``engine_options`` argument is given to :class:`.SQLAlchemy`, it sets default options for *all* engines. :data:`SQLALCHEMY_ECHO` sets the default value for both ``echo`` and ``echo_pool`` for all engines. - The options for each engine in :data:`.SQLALCHEMY_BINDS` override those defaults. - :data:`.SQLALCHEMY_ENGINE_OPTIONS` overrides the ``None`` key in ``SQLALCHEMY_BINDS``, and :data:`.SQLALCHEMY_DATABASE_URI` overrides the ``url`` key in that engine's options. Timeouts -------- Certain databases may be configured to close inactive connections after a period of time. MySQL and MariaDB are configured for this by default, but database services may also configure this type of limit. This can result in an error like ``2013: Lost connection to MySQL server during query``. If you encounter this error, try setting ``pool_recycle`` in the engine options to a value less than the database's timeout. Alternatively, you can try setting ``pool_pre_ping`` if you expect the database to close connections often, such as if it's running in a container that may restart. See SQLAlchemy's docs on `dealing with disconnects`_ for more information. .. _dealing with disconnects: https://docs.sqlalchemy.org/core/pooling.html#dealing-with-disconnects --- ## File: docs/contexts.rst Flask Application Context ========================= An active Flask application context is required to make queries and to access ``db.engine`` and ``db.session``. This is because the session is scoped to the context so that it is cleaned up properly after every request or CLI command. Regardless of how an application is initialized with the extension, it is not stored for later use. Instead, the extension uses Flask's ``current_app`` proxy to get the active application, which requires an active application context. Automatic Context ----------------- When Flask is handling a request or a CLI command, an application context will automatically be pushed. Therefore you don't need to do anything special to use the database during requests or CLI commands. Manual Context -------------- If you try to use the database when an application context is not active, you will see the following error. .. code-block:: text RuntimeError: Working outside of application context. This typically means that you attempted to use functionality that needed the current application. To solve this, set up an application context with app.app_context(). See the documentation for more information. If you find yourself in a situation where you need the database and don't have a context, you can push one with ``app_context``. This is common when calling ``db.create_all`` to create the tables, for example. .. code-block:: python def create_app(): app = Flask(__name__) app.config.from_object("project.config") import project.models with app.app_context(): db.create_all() return app Tests ----- If you test your application using the Flask test client to make requests to your endpoints, the context will be available as part of the request. If you need to test something about your database or models directly, rather than going through a request, you need to push a context manually. Only push a context exactly where and for how long it's needed for each test. Do not push an application context globally for every test, as that can interfere with how the session is cleaned up. .. code-block:: python def test_user_model(app): user = User() with app.app_context(): db.session.add(user) db.session.commit() If you find yourself writing many tests like that, you can use a pytest fixture to push a context for a specific test. .. code-block:: python import pytest @pytest.fixture def app_ctx(app): with app.app_context(): yield @pytest.mark.usefixtures("app_ctx") def test_user_model(): user = User() db.session.add(user) db.session.commit() --- ## File: docs/customizing.rst Advanced Customization ====================== The various objects managed by the extension can be customized by passing arguments to the :class:`.SQLAlchemy` constructor. Model Class ----------- SQLAlchemy models all inherit from a declarative base class. This is exposed as ``db.Model`` in Flask-SQLAlchemy, which all models extend. This can be customized by subclassing the default and passing the custom class to ``model_class``. The following example gives every model an integer primary key, or a foreign key for joined-table inheritance. .. note:: Integer primary keys for everything is not necessarily the best database design (that's up to your project's requirements), this is only an example. .. code-block:: python from sqlalchemy import Integer, String, ForeignKey from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, declared_attr class Base(DeclarativeBase): @declared_attr.cascading @classmethod def id(cls): for base in cls.__mro__[1:-1]: if getattr(base, "__table__", None) is not None: return mapped_column(ForeignKey(base.id), primary_key=True) else: return mapped_column(Integer, primary_key=True) db = SQLAlchemy(app, model_class=Base) class User(db.Model): name: Mapped[str] class Employee(User): title: Mapped[str] Abstract Models and Mixins -------------------------- If behavior is only needed on some models rather than all models, use an abstract model base class to customize only those models. For example, if some models should track when they are created or updated. .. code-block:: python from datetime import datetime, timezone from sqlalchemy.orm import Mapped, mapped_column class TimestampModel(db.Model): __abstract__ = True created: Mapped[datetime] = mapped_column(default=lambda: datetime.now(timezone.utc)) updated: Mapped[datetime] = mapped_column(default=lambda: datetime.now(timezone.utc), onupdate=lambda: datetime.now(timezone.utc)) class Author(db.Model): id: Mapped[int] = mapped_column(primary_key=True) username: Mapped[str] = mapped_column(unique=True) class Post(TimestampModel): id: Mapped[int] = mapped_column(primary_key=True) title: Mapped[str] This can also be done with a mixin class, inheriting from ``db.Model`` separately. .. code-block:: python class TimestampMixin: created: Mapped[datetime] = mapped_column(default=lambda: datetime.now(timezone.utc)) updated: Mapped[datetime] = mapped_column(default=lambda: datetime.now(timezone.utc), onupdate=lambda: datetime.now(timezone.utc)) class Post(TimestampMixin, db.Model): id: Mapped[int] = mapped_column(primary_key=True) title: Mapped[str] Disabling Table Name Generation ------------------------------- Some projects prefer to set each model's ``__tablename__`` manually rather than relying on Flask-SQLAlchemy's detection and generation. The simple way to achieve that is to set each ``__tablename__`` and not modify the base class. However, the table name generation can be disabled by setting `disable_autonaming=True` in the `SQLAlchemy` constructor. .. code-block:: python class Base(sa_orm.DeclarativeBase): pass db = SQLAlchemy(app, model_class=Base, disable_autonaming=True) Session Class ------------- Flask-SQLAlchemy's :class:`.Session` class chooses which engine to query based on the bind key associated with the model or table. However, there are other strategies such as horizontal sharding that can be implemented with a different session class. The ``class_`` key to the ``session_options`` argument to the extension to change the session class. Flask-SQLAlchemy will always pass the extension instance as the ``db`` argument to the session, so it must accept that to continue working. That can be used to get access to ``db.engines``. .. code-block:: python from sqlalchemy.ext.horizontal_shard import ShardedSession from flask_sqlalchemy.session import Session class CustomSession(ShardedSession, Session): ... db = SQLAlchemy(session_options={"class_": CustomSession}) Query Class ----------- .. warning:: The query interface is considered legacy in SQLAlchemy. This includes ``session.query``, ``Model.query``, ``db.Query``, and ``lazy="dynamic"`` relationships. Prefer using ``session.execute(select(...))`` instead. It is possible to customize the query interface used by the session, models, and relationships. This can be used to add extra query methods. For example, you could add a ``get_or`` method that gets a row or returns a default. .. code-block:: python from flask_sqlalchemy.query import Query class GetOrQuery(Query): def get_or(self, ident, default=None): out = self.get(ident) if out is None: return default return out db = SQLAlchemy(query_class=GetOrQuery) user = User.query.get_or(user_id, anonymous_user) Passing the ``query_class`` argument will customize ``db.Query``, ``db.session.query``, ``Model.query``, and ``db.relationship(lazy="dynamic")`` relationships. It's also possible to customize these on a per-object basis. To customize a specific model's ``query`` property, set the ``query_class`` attribute on the model class. .. code-block:: python class User(db.Model): query_class = GetOrQuery To customize a specific dynamic relationship, pass the ``query_class`` argument to the relationship. .. code-block:: python db.relationship(User, lazy="dynamic", query_class=GetOrQuery) To customize only ``session.query``, pass the ``query_cls`` key to the ``session_options`` argument to the constructor. .. code-block:: python db = SQLAlchemy(session_options={"query_cls": GetOrQuery}) --- ## File: docs/index.rst .. rst-class:: hide-header Flask-SQLAlchemy ================ .. image:: _static/flask-sqlalchemy-title.png :align: center Flask-SQLAlchemy is an extension for `Flask`_ that adds support for `SQLAlchemy`_ to your application. It simplifies using SQLAlchemy with Flask by setting up common objects and patterns for using those objects, such as a session tied to each web request, models, and engines. Flask-SQLAlchemy does not change how SQLAlchemy works or is used. See the `SQLAlchemy documentation`_ to learn how to work with the ORM in depth. The documentation here will only cover setting up the extension, not how to use SQLAlchemy. .. _SQLAlchemy: https://www.sqlalchemy.org/ .. _Flask: https://flask.palletsprojects.com/ .. _SQLAlchemy documentation: https://docs.sqlalchemy.org/ User Guide ---------- .. toctree:: :maxdepth: 2 quickstart config models queries pagination contexts binds record-queries track-modifications customizing API Reference ------------- .. toctree:: :maxdepth: 2 api Additional Information ---------------------- .. toctree:: :maxdepth: 2 license changes --- ## File: docs/legacy-query.rst :orphan: Legacy Query Interface ====================== .. warning:: The query interface is considered legacy in SQLAlchemy. Prefer using ``session.execute(select(...))`` instead. Flask-SQLAlchemy adds a ``query`` object to each model. This can be used to query instances of a given model. ``User.query`` is a shortcut for ``db.session.query(User)``. .. code-block:: python # get the user with id 5 user = User.query.get(5) # get a user by username user = User.query.filter_by(username=username).one() Queries for Views ----------------- If you write a Flask view function it's often useful to return a ``404 Not Found`` error for missing entries. Flask-SQLAlchemy provides some extra query methods. - :meth:`.Query.get_or_404` will raise a 404 if the row with the given id doesn't exist, otherwise it will return the instance. - :meth:`.Query.first_or_404` will raise a 404 if the query does not return any results, otherwise it will return the first result. - :meth:`.Query.one_or_404` will raise a 404 if the query does not return exactly one result, otherwise it will return the result. .. code-block:: python @app.route("/user/") def show_user(username): user = User.query.filter_by(username=username).one_or_404() return render_template("show_user.html", user=user) You can add a custom message to the 404 error: .. code-block:: python user = User.query.filter_by(username=username).one_or_404( description=f"No user named '{username}'." ) Pagination ---------- If you have a lot of results, you may only want to show a certain number at a time, allowing the user to click next and previous links to see pages of data. Call :meth:`~.Query.paginate` on a query to get a :class:`.Pagination` object. See :doc:`/pagination` for more information about the pagination object. During a request, this will take ``page`` and ``per_page`` arguments from the query string ``request.args``. Pass ``max_per_page`` to prevent users from requesting too many results on a single page. If not given, the default values will be page 1 with 20 items per page. .. code-block:: python page = User.query.order_by(User.join_date).paginate() return render_template("user/list.html", page=page) --- ## File: docs/legacy-quickstart.rst :orphan: Legacy Quickstart ====================== .. warning:: This guide shows you how to initialize the extension and define models when using the SQLAlchemy 1.x style of ORM model classes. We encourage you to upgrade to `SQLAlchemy 2.x`_ to take advantage of the new typed model classes. .. _SQLAlchemy 2.x: https://docs.sqlalchemy.org/en/20/orm/quickstart.html Initialize the Extension ------------------------ First create the ``db`` object using the ``SQLAlchemy`` constructor. When using the SQLAlchemy 1.x API, you do not need to pass any arguments to the ``SQLAlchemy`` constructor. A declarative base class will be created behind the scenes for you. .. code-block:: python from flask import Flask from flask_sqlalchemy import SQLAlchemy from sqlalchemy.orm import DeclarativeBase db = SQLAlchemy() Using custom MetaData and naming conventions -------------------------------------------- You can optionally construct the :class:`.SQLAlchemy` object with a custom :class:`~sqlalchemy.schema.MetaData` object. This allows you to specify a custom constraint `naming convention`_. This makes constraint names consistent and predictable, useful when using migrations, as described by `Alembic`_. .. code-block:: python from sqlalchemy import MetaData from flask_sqlalchemy import SQLAlchemy db = SQLAlchemy(metadata=MetaData(naming_convention={ "ix": 'ix_%(column_0_label)s', "uq": "uq_%(table_name)s_%(column_0_name)s", "ck": "ck_%(table_name)s_%(constraint_name)s", "fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s", "pk": "pk_%(table_name)s" })) .. _naming convention: https://docs.sqlalchemy.org/core/constraints.html#constraint-naming-conventions .. _Alembic: https://alembic.sqlalchemy.org/en/latest/naming.html Define Models ------------- Subclass ``db.Model`` to define a model class. This is a SQLAlchemy declarative base class, it will take ``Column`` attributes and create a table. .. code-block:: python class User(db.Model): id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String, unique=True, nullable=False) email = db.Column(db.String) For convenience, the extension object provides access to names in the ``sqlalchemy`` and ``sqlalchemy.orm`` modules. So you can use ``db.Column`` instead of importing and using ``sqlalchemy.Column``, although the two are equivalent. Unlike plain SQLAlchemy, Flask-SQLAlchemy's model will automatically generate a table name if ``__tablename__`` is not set and a primary key column is defined. The table name ``"user"`` will automatically be assigned to the model's table. Create the Tables ----------------- Defining a model does not create it in the database. Use :meth:`~.SQLAlchemy.create_all` to create the models and tables after defining them. If you define models in submodules, you must import them so that SQLAlchemy knows about them before calling ``create_all``. .. code-block:: python with app.app_context(): db.create_all() Querying the Data ----------------- You can query the data the same way regardless of SQLAlchemy version. See :doc:`queries` for more information about queries. --- METRICS --- - Files Extracted: 10 - Estimated Token Budget: ~7701 tokens - Recency Window: Active (< 180 days) - Canonical Reference: https://codewiki.google/github.com/pallets-eco/flask-sqlalchemy