Redesign1 #1
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.ini
|
||||||
alembic/
|
alembic/
|
||||||
*.egg-info/
|
*.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