Customizing
***********

Flask-SQLAlchemy defines sensible defaults. However, sometimes
customization is needed. There are various ways to customize how the
models are defined and interacted with.

These customizations are applied at the creation of the "SQLAlchemy"
object and extend to all models derived from its "Model" class.


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.

   from flask_sqlalchemy import Model, SQLAlchemy
   import sqlalchemy as sa
   from sqlalchemy.ext.declarative import declared_attr, has_inherited_table

   class IdModel(Model):
       @declared_attr
       def id(cls):
           for base in cls.__mro__[1:-1]:
               if getattr(base, '__table__', None) is not None:
                   type = sa.ForeignKey(base.id)
                   break
           else:
               type = sa.Integer

           return sa.Column(type, primary_key=True)

   db = SQLAlchemy(model_class=IdModel)

   class User(db.Model):
       name = db.Column(db.String)

   class Employee(User):
       title = db.Column(db.String)


Model Mixins
============

If behavior is only needed on some models rather than all models, use
mixin classes to customize only those models. For example, if some
models should track when they are created or updated:

   from datetime import datetime

   class TimestampMixin(object):
       created = db.Column(
           db.DateTime, nullable=False, default=datetime.utcnow)
       updated = db.Column(db.DateTime, onupdate=datetime.utcnow)

   class Author(db.Model):
       ...

   class Post(TimestampMixin, db.Model):
       ...


Query Class
===========

It is also possible to customize what is available for use on the
special "query" property of models. For example, providing a "get_or"
method:

   from flask_sqlalchemy import BaseQuery, SQLAlchemy

   class GetOrQuery(BaseQuery):
       def get_or(self, ident, default=None):
           return self.get(ident) or default

   db = SQLAlchemy(query_class=GetOrQuery)

   # get a user by id, or return an anonymous user instance
   user = User.query.get_or(user_id, anonymous_user)

And now all queries executed from the special "query" property on
Flask-SQLAlchemy models can use the "get_or" method as part of their
queries. All relationships defined with "db.relationship" (but not
"sqlalchemy.orm.relationship()") will also be provided with this
functionality.

It also possible to define a custom query class for individual
relationships as well, by providing the "query_class" keyword in the
definition. This works with both "db.relationship" and
"sqlalchemy.relationship":

   class MyModel(db.Model):
       cousin = db.relationship('OtherModel', query_class=GetOrQuery)

Note:

  If a query class is defined on a relationship, it will take
  precedence over the query class attached to its corresponding model.

It is also possible to define a specific query class for individual
models by overriding the "query_class" class attribute on the model:

   class MyModel(db.Model):
       query_class = GetOrQuery

In this case, the "get_or" method will be only availble on queries
orginating from "MyModel.query".


Model Metaclass
===============

Warning:

  Metaclasses are an advanced topic, and you probably don't need to
  customize them to achieve what you want. It is mainly documented
  here to show how to disable table name generation.

The model metaclass is responsible for setting up the SQLAlchemy
internals when defining model subclasses. Flask-SQLAlchemy adds some
extra behaviors through mixins; its default metaclass, "DefaultMeta",
inherits them all.

* "BindMetaMixin": "__bind_key__" is extracted from the class and
  applied to the table. See Multiple Databases with Binds.

* "NameMetaMixin": If the model does not specify a "__tablename__" but
  does specify a primary key, a name is automatically generated.

You can add your own behaviors by defining your own metaclass and
creating the declarative base yourself. Be sure to still inherit from
the mixins you want (or just inherit from the default metaclass).

Passing a declarative base class instead of a simple model base class,
as shown above, to "base_class" will cause Flask-SQLAlchemy to use
this base instead of constructing one with the default metaclass.

   from flask_sqlalchemy import SQLAlchemy
   from flask_sqlalchemy.model import DefaultMeta, Model

   class CustomMeta(DefaultMeta):
       def __init__(cls, name, bases, d):
           # custom class setup could go here

           # be sure to call super
           super(CustomMeta, cls).__init__(name, bases, d)

       # custom class-only methods could go here

   db = SQLAlchemy(model_class=declarative_base(
       cls=Model, metaclass=CustomMeta, name='Model'))

You can also pass whatever other arguments you want to
"declarative_base()" to customize the base class as needed.


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 table name generation can be disabled by defining a custom
metaclass.

   from flask_sqlalchemy.model import BindMetaMixin, Model
   from sqlalchemy.ext.declarative import DeclarativeMeta, declarative_base

   class NoNameMeta(BindMetaMixin, DeclarativeMeta):
       pass

   db = SQLAlchemy(model_class=declarative_base(
       cls=Model, metaclass=NoNameMeta, name='Model'))

This creates a base that still supports the "__bind_key__" feature but
does not generate table names.
