Работа с плагинами¶
Подключение плагинов¶
Плагины подключаются в момент инициализации JSON API. Рассмотрим пример подключения плагина EventPlugin
from flask import Flask
from flask_combo_jsonapi import Api
from combojsonapi.event import EventPlugin
app = Flask(__name__)
api_json = Api(
app,
plugins=[
EventPlugin(),
]
)
API для плагинов¶
При реализации плагина доступны следующие hooks
before_init_plugin(self, *args, app=None, **kwargs) -> None
срабатывает перед инициализацией json_api
app- ссылка на объект приложения Flask.
after_init_plugin(self, *args, app=None, **kwargs) -> None
срабатывает после инициализации json_api
app- ссылка на объект приложения Flask.
before_route(self, resource: Union[ResourceList, ResourceDetail] = None, view=None, urls: Tuple[str] = None, self_json_api: Api = None, **kwargs) -> None:
Предобработка ресурс менеджеров до создания роутеров
resource- ресурс менеджер;
view- название ресурс менеджера;
urls- список url, по которым будет доступен данный ресурс;
self_json_api- ссылка на объект Api.
after_route(self, resource: Union[ResourceList, ResourceDetail] = None, view=None, urls: Tuple[str] = None, self_json_api: Api = None, **kwargs) -> None:
Постобработка ресурс менеджеров после создания роутеров
resource- ресурс менеджер;
view- название ресурс менеджера;
urls- список url, по которым будет доступен данный ресурс;
self_json_api- ссылка на объект Api.
after_init_schema_in_resource_list_post(self, *args, schema=None, model=None, **kwargs) -> None
Выполняется после инициализация marshmallow схемы в ResourceList.post
schema- схема, которая привязана к ресурсу для сериализации/десериализации;
model- модель, которая привязана к ресурсу.
after_init_schema_in_resource_list_get(self, *args, schema=None, model=None, **kwargs) -> None
Выполняется после инициализация marshmallow схемы в ResourceList.get
schema- схема, которая привязана к ресурсу для сериализации/десериализации;
model- модель, которая привязана к ресурсу.
after_init_schema_in_resource_detail_get(self, *args, schema=None, model=None, **kwargs) -> None
Выполняется после инициализация marshmallow схемы в ResourceDetail.get
schema- схема, которая привязана к ресурсу для сериализации/десериализации;
model- модель, которая привязана к ресурсу.
after_init_schema_in_resource_detail_patch(self, *args, schema=None, model=None, **kwargs) -> None
Выполняется после инициализация marshmallow схемы в ResourceDetail.patch
schema- схема, которая привязана к ресурсу для сериализации/десериализации;
model- модель, которая привязана к ресурсу.
data_layer_before_create_object(self, *args, data=None, view_kwargs=None, self_json_api=None, **kwargs) -> None
Выполняется после десериализации данных и до создания запроса к бд на создание нового объекта
data- десериализованнаые данные для создания объекта;
view_kwargs- kwargs из ресурс менеджера;
self_json_api- ссылка на объект Api.
data_layer_create_object_clean_data(self, *args, data: Dict = None, view_kwargs=None, join_fields: List[str] = None, self_json_api=None, **kwargs) -> Dict
Обрабатывает данные, которые пойдут непосредственно на создание нового объекта. Возвращает обновлённый набор данных для нового объекта
Dict data- сырые данные, на основе которых будет создан новый объект;
view_kwargs- kwargs из ресурс менеджера;
List[str] join_fields- список полей, которые являются ссылками на другие модели;
self_json_api- ссылка на объект Api.
data_layer_after_create_object(self, *args, data=None, view_kwargs=None, self_json_api=None, obj=None, **kwargs) -> None
Выполняется после создание нового объекта, но до сохранения в БД
Dict data- данные, использованные для создания нового объекта;
view_kwargs- kwargs из ресурс менеджера;
obj- новый объект, созданный на основе data;
self_json_api- ссылка на объект Api.
data_layer_get_object_update_query(self, *args, query: Query = None, qs: QueryStringManager = None, view_kwargs=None, self_json_api=None, **kwargs) -> Query
Вызывается во время создания запроса к БД на обновление объекта. Тут можно пропатчить запрос к БД. Возвращает пропатченный запрос к бд
Query query- сформированный запрос к БД;
QueryStringManager qs- список параметров для запроса;
view_kwargs- kwargs из ресурс менеджера;
self_json_api- ссылка на объект Api.
data_layer_get_collection_update_query(self, *args, query: Query = None, qs: QueryStringManager = None, view_kwargs=None, self_json_api=None, **kwargs) -> Query
Во время создания запроса к БД на обновление объектов. Тут можно пропатчить запрос к БД. Возвращает пропатченный запрос к бд
Query query- сформированный запрос к БД;
QueryStringManager qs- список параметров для запроса;
view_kwargs- kwargs из ресурс менеджера;
self_json_api- ссылка на объект Api.
data_layer_update_object_clean_data(self, *args, data: Dict = None, obj=None, view_kwargs=None, join_fields: List[str] = None, self_json_api=None, **kwargs) -> Dict
Обрабатывает данные, которые пойдут непосредственно на обновления объекта. Возвращает обновлённый набор данных data для обновления объекта
Dict data- данные, которыми будет обновлён объект;
obj- редактируемый объект;
view_kwargs- kwargs из ресурс менеджера;
self_json_api- ссылка на объект Api.
List[str] join_fields- список полей, которые являются ссылками на другие модели.
data_layer_delete_object_clean_data(self, *args, obj=None, view_kwargs=None, self_json_api=None, **kwargs) -> None
Выполняется до удаления объекта из БД
obj- удаляемый объект;
view_kwargs- kwargs из ресурс менеджера;
self_json_api- ссылка на объект Api.
before_data_layers_filtering_alchemy_nested_resolve(self, self_nested: Any) -> None
Вызывается до создания фильтра в функции Nested.resolve, если после выполнения вернёт None, то дальше продолжится работа функции resolve, если вернёт какое либо значения отличное от None, то функция resolve завершается, а результат hook функции передаётся дальше в стеке вызова.
self_nested- экземплярNested.
before_data_layers_sorting_alchemy_nested_resolve(self, self_nested: Any) -> None
Called before sort is created in Nested.resolve. When returns None,
resolvecontinues executing; when returns any other value,resolveexits, and the hook function result is passed further in the call stack.
self_nested- экземплярNested.
Пример создания плагинов¶
Рассмотрим пример реализации плагина, который будет отдавать данные в get запросах для ResourceList, ResourceDetail в двух вариантах либо все, либо укороченные по заранее заданному параметру format=short|full
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import Column, Integer, String
from sqlalchemy.orm import Query, load_only, scoped_session
from combojsonapi.utils import Relationship
from flask_combo_jsonapi import Api, ResourceList, ResourceDetail
from flask_combo_jsonapi.plugin import BasePlugin
from flask_combo_jsonapi.querystring import QueryStringManager
from marshmallow_jsonapi.flask import Schema
from marshmallow_jsonapi import fields
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///:memory:'
app.config['SQLALCHEMY_ECHO'] = True
db = SQLAlchemy(app)
app.config['FLASK_DEBUG'] = 1
class User(db.Model):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String)
fullname = Column(String)
email = Column(String)
password = Column(String)
db.create_all()
class UserSchema(Schema):
class Meta:
type_ = 'user'
self_view = 'user_detail'
self_view_kwargs = {'id': '<id>'}
self_view_many = 'user_list'
ordered = True
id = fields.Integer(as_string=True)
name = fields.String()
fullname = fields.String()
email = fields.String()
password = fields.String()
class UserResourceList(ResourceList):
schema = UserSchema
method = ['GET']
data_layer = {
'session': db.session,
'model': User,
'short_format': ['id', 'name']
}
class UserResourceDetail(ResourceDetail):
schema = UserSchema
method = ['GET']
data_layer = {
'session': db.session,
'model': User,
'short_format': ['id', 'name']
}
class FormatPlugin(BasePlugin):
def _update_query(self, *args, query: Query = None, qs: QueryStringManager = None,
view_kwargs=None, self_json_api=None, **kwargs) -> Query:
all_fields = self_json_api.model.__mapper__.column_attrs.keys()
short_format = self_json_api.short_format if hasattr(self_json_api, 'short_format') else all_fields
full_format = self_json_api.full_format if hasattr(self_json_api, 'full_format') else all_fields
fields = short_format if qs.qs.get('format') == 'short' else full_format
query = self_json_api.session.query(*[getattr(self_json_api.model, name_field) for name_field in fields])
return query
def data_layer_get_object_update_query(self, *args, query: Query = None, qs: QueryStringManager = None,
view_kwargs=None, self_json_api=None, **kwargs) -> Query:
return self._update_query(*args, query=query, qs=qs, view_kwargs=view_kwargs,
self_json_api=self_json_api, **kwargs)
def data_layer_get_collection_update_query(self, *args, query: Query = None, qs: QueryStringManager = None,
view_kwargs=None, self_json_api=None, **kwargs) -> Query:
return self._update_query(*args, query=query, qs=qs, view_kwargs=view_kwargs,
self_json_api=self_json_api, **kwargs)
api_json = Api(
app,
plugins=[
FormatPlugin(),
]
)
api_json.route(UserResourceList, 'user_list', '/api/user/')
api_json.route(UserResourceDetail, 'user_detail', '/api/user/<int:id>/')
if __name__ == '__main__':
for i in range(10):
u = User(name=f'name{i}', fullname=f'fullname{i}', email=f'email{i}', password=f'password{i}')
db.session.add(u)
db.session.commit()
app.run(use_reloader=True)