|
| 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