Initial framework.
This commit is contained in:
parent
e8755fae4d
commit
42e9710f48
7 changed files with 98 additions and 1 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -10,3 +10,4 @@ inventory/static/uploads/*
|
|||
alembic.ini
|
||||
alembic/
|
||||
*.egg-info/
|
||||
test-app/
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
from flask import Blueprint, jsonify, request
|
||||
|
||||
def generate_crud_blueprint(model, service):
|
||||
bp = Blueprint(model.__name__.lower(), __name__)
|
||||
|
||||
@bp.get('/')
|
||||
def list_items():
|
||||
items = service.list()
|
||||
return jsonify([item.as_dict() for item in items])
|
||||
|
||||
@bp.get('/<int:id>')
|
||||
def get_item(id):
|
||||
item = service.get(id)
|
||||
return jsonify(item.as_dict())
|
||||
|
||||
@bp.post('/')
|
||||
def create_item():
|
||||
obj = service.create(request.json)
|
||||
return jsonify(obj.as_dict())
|
||||
|
||||
@bp.patch('/<int:id>')
|
||||
def update_item(id):
|
||||
obj = service.update(id, request.json)
|
||||
return jsonify(obj.as_dict())
|
||||
|
||||
@bp.delete('/<int:id>')
|
||||
def delete_item(id):
|
||||
service.delete(id)
|
||||
return '', 204
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
from sqlalchemy import Column, Integer, DateTime, func
|
||||
from sqlalchemy.orm import declarative_mixin
|
||||
|
||||
@declarative_mixin
|
||||
class CRUDMixin:
|
||||
id = Column(Integer, primary_key=True)
|
||||
created_at = Column(DateTime, default=func.now())
|
||||
updated_at = Column(DateTime, default=func.now(), onupdate=func.now())
|
||||
|
||||
def as_dict(self):
|
||||
return {c.name: getattr(self, c.name) for c in self.__table__.columns}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
from typing import Type, TypeVar, Generic
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
class CRUDService(Generic[T]):
|
||||
def __init__(self, model: Type[T], session: Session):
|
||||
self.model = model
|
||||
self.session = session
|
||||
|
||||
def get(self, id: int) -> T:
|
||||
return self.session.get(self.model, id)
|
||||
|
||||
def list(self, limit=100, offset=0) -> list[T]:
|
||||
return self.session.query(self.model).offset(offset).limit(limit).all()
|
||||
|
||||
def create(self, data: dict) -> T:
|
||||
obj = self.model(**data)
|
||||
self.session.add(obj)
|
||||
self.session.commit()
|
||||
return obj
|
||||
|
||||
def update(self, id: int, data: dict) -> T:
|
||||
obj = self.get(id)
|
||||
for k, v in data.items():
|
||||
setattr(obj, k, v)
|
||||
self.session.commit()
|
||||
return obj
|
||||
|
||||
def delete(self, id: int):
|
||||
obj = self.get(id)
|
||||
self.session.delete(obj)
|
||||
self.session.commit()
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
from jinja2 import Environment, FileSystemLoader
|
||||
import os
|
||||
|
||||
FRAGMENT_PATH = os.path.join(os.path.dirname(__file__), 'templates')
|
||||
env = Environment(loader=FileSystemLoader(FRAGMENT_PATH))
|
||||
|
||||
def render_field(field_name, value):
|
||||
template = env.get_template('field.html')
|
||||
return template.render(field_name=field_name, value=value)
|
||||
|
||||
def render_table(objects):
|
||||
template = env.get_template('table.html')
|
||||
return template.render(objects=objects)
|
||||
2
crudkit/ui/templates/field.html
Normal file
2
crudkit/ui/templates/field.html
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
<label>{{ field_name }}</label>
|
||||
<input type="text" name="{{ field_name }}" value="{{ value }}">
|
||||
8
crudkit/ui/templates/table.html
Normal file
8
crudkit/ui/templates/table.html
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
<table>
|
||||
<tr>
|
||||
{% for field in objects[0].__table__.columns %}<th>{{ field.name }}</th>{% endfor %}
|
||||
</tr>
|
||||
{% for obj in objects %}
|
||||
<tr>{% for field in obj.__table__columns %}<td>{{ getattr(obj, field.name) }}</td>{% endfor %}</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
Loading…
Add table
Add a link
Reference in a new issue