Плагин PostgreSqlJSONB¶
Плагин PostgreSqlJSONB позволяет:
Работать с типом полей JSONB в PostgreSql как с обычной моделью в плане выгрузки на клиент. Работает это для get запросов в фильтрации и сортировке. Работать можно с полями первого уровня.
Интегрируется с плагином ApiSpecPlugin в swagger в get запросах (когда выгружается ResourceList). Появились доп. поля:
filter[<название JSONB поля в модели>.<название поля верхнего уровня в JSONB>]- обычные фильтрыfilter = [{"name": "<название JSONB поля в модели>__<название\поля верхнего уровня в JSONB>", "op": "eq", "val": "<значение>"}]- в составных фильтрах также обращаемся к полям внутри JSONB поля, как к полям другой модели.sort=<название JSONB поля в модели>.<название поля верхнего уровня в JSONB>- в сортировке используется как глубокая сортировка.
Интегрируется с плагином PermissionPlugin, можно в пермишен кейсах описать ограничения на поля верхнего уровня в поле модели JSONB.
Работа с плагином¶
Чтобы интегрировать плагин в свои схемы, в которых описаны модели с полями JSONB, нужно сделать следующее:
В схеме описываем поле JSONB (из модели) как Nested, на схему со структурой того, что планируется хранить в JSONB
Схема созданная в первом пункте для хранения структуры из поля модели JSONB должно наследоваться от класса
combojsonapi.postgresql_jsonb.schema.SchemaJSONB
И всё :)
Пример подключения плагина¶
Рассмотрим пример, когда в поле JSONB будем хранить настройки пользователя. Пример будет работать только с подключение к базе данных postgresql
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import Column, Integer, String
from sqlalchemy.dialects.postgresql.json import JSONB
from sqlalchemy.orm import Query, load_only, scoped_session
from flask_combo_jsonapi.marshmallow_fields import Relationship
from flask_combo_jsonapi import Api, ResourceList, ResourceDetail
from flask_combo_jsonapi.querystring import QueryStringManager
from combojsonapi.postgresql_jsonb.schema import SchemaJSONB
from combojsonapi.postgresql_jsonb import PostgreSqlJSONB
from combojsonapi.spec import ApiSpecPlugin
from marshmallow_jsonapi.flask import Schema
from marshmallow_jsonapi import fields
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = '<подключение к Postgresql базе данных>'
app.config['SQLALCHEMY_ECHO'] = True
db = SQLAlchemy(app)
"""Models description"""
class User(db.Model):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String)
fullname = Column(String)
email = Column(String)
password = Column(String)
settings = Column(JSONB)
db.create_all()
"""Models' schemas description"""
class SettingsSchema(SchemaJSONB):
active = fields.Boolean()
age = fields.Integer()
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()
settings = fields.Nested('SettingsSchema')
"""API resource managers description"""
class UserResourceDetail(ResourceDetail):
schema = UserSchema
events = UserEventsForResourceDetail
methods = ['GET']
data_layer = {
'session': db.session,
'model': User,
}
class UserResourceList(ResourceList):
schema = UserSchema
methods = ['GET', 'POST']
data_layer = {
'session': db.session,
'model': User,
}
"""Initializing the API"""
app.config['OPENAPI_URL_PREFIX'] = '/api/swagger'
app.config['OPENAPI_SWAGGER_UI_PATH'] = '/'
app.config['OPENAPI_SWAGGER_UI_VERSION'] = '3.22.0'
api_spec_plagin = ApiSpecPlugin(
app=app,
# Declaring tags list with their descriptions, so API gets organized into groups. This is optional: when there's no tags,
# api will be grouped automatically by type schemas names (type_)
tags={
'User': 'API для user'
}
)
api_json = Api(
app,
plugins=[
api_spec_plagin,
EventPlugin(),
PostgreSqlJSONB()
]
)
api_json.route(UserResourceDetail, 'user_detail', '/api/user/<int:id>/', tag='User')
api_json.route(UserResourceList, 'user_list', '/api/user/', tag='User')
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(port='9999')
Пример использования в запросах¶
С views, описанными в примере выше, мы можем пользоваться новыми фильтрами и сортировкой.
Запрос всех активных пользователей простым фильтром:
/api/user/?filter[settings.active]=True
Запрос всех совершеннолетних пользователей (сложный фильтр), сортированных по возрасту по убыванию, затем по имени по возрастанию:
/api/user/?filter=[{"name":"settings.age","op": "gt","val": "18"}]&sort=-settings.age,name