crudkit/crudkit/blueprint.py
2025-08-26 09:01:15 -05:00

81 lines
No EOL
3.1 KiB
Python

from flask import Blueprint, request, jsonify, abort
from sqlalchemy.orm import scoped_session
from .dsl import QuerySpec
from .service import CrudService
from .eager import default_eager_policy
from .serialize import serialize
def make_blueprint(db_session_factory, registry):
bp = Blueprint("crud", __name__)
def session(): return scoped_session(db_session_factory)()
@bp.get("/<model>/list")
def list_items(model):
Model = registry.get(model) or abort(404)
spec = QuerySpec(
filters=_parse_filters(request.args),
order_by=request.args.getlist("sort"),
page=request.args.get("page", type=int),
per_page=request.args.get("per_page", type=int),
expand=request.args.getlist("expand"),
fields=request.args.get("fields", type=lambda s: [x.strip() for x in s.split(",")] if s else None),
)
s = session(); svc = CrudService(s, default_eager_policy)
rows, total = svc.list(Model, spec)
data = [serialize(r, fields=spec.fields, expand=spec.expand) for r in rows]
return jsonify({"data": data, "total": total})
@bp.post("/<model>")
def create_item(model):
Model = registry.get(model) or abort(404)
payload = request.get_json() or {}
s = session(); svc = CrudService(s, default_eager_policy)
obj = svc.create(Model, payload)
s.commit()
return jsonify(serialize(obj)), 201
@bp.get("/<model>/<int:id>")
def read_item(model, id):
Model = registry.get(model) or abort(404)
spec = QuerySpec(expand=request.args.getlist("expand"),
fields=request.args.get("fields", type=lambda s: s.split(",")))
s = session(); svc = CrudService(s, default_eager_policy)
obj = svc.get(Model, id, spec) or abort(404)
return jsonify(serialize(obj, fields=spec.fields, expand=spec.expand))
@bp.patch("/<model>/<int:id>")
def update_item(model, id):
Model = registry.get(model) or abort(404)
s = session(); svc = CrudService(s, default_eager_policy)
obj = svc.get(Model, id, QuerySpec()) or abort(404)
payload = request.get_json() or {}
svc.update(obj, payload)
s.commit()
return jsonify(serialize(obj))
@bp.delete("/<model>/<int:id>")
def delete_item(model, id):
Model = registry.get(model) or abort(404)
s = session(); svc = CrudService(s, default_eager_policy)
obj = svc.get(Model, id, QuerySpec()) or abort(404)
svc.soft_delete(obj)
s.commit()
return jsonify({"status": "deleted"})
@bp.post("/<model>/<int:id>/undelete")
def undelete_item(model, id):
Model = registry.get(model) or abort(404)
s = session(); svc = CrudService(s, default_eager_policy)
obj = svc.get(Model, id, QuerySpec()) or abort(404)
svc.undelete(obj)
s.commit()
return jsonify({"status": "restored"})
return bp
def _parse_filters(args):
out = {}
for k, v in args.items():
if k in {"page", "per_page", "sort", "expand", "fields"}:
continue
out[k] = v
return out