Fix a lot of missing relationship information, plus some upstream CRUDKit changes.

This commit is contained in:
Yaro Kasear 2025-09-05 09:45:22 -05:00
parent 8643d177ca
commit cf56baabe2
11 changed files with 82 additions and 22 deletions

View file

@ -3,7 +3,10 @@ import os
from flask import Flask
from .db import init_db, create_all_tables
from crudkit.api.flask_api import generate_crud_blueprint
from crudkit.core.service import CRUDService
from .db import init_db, create_all_tables, get_session
def create_app() -> Flask:
app = Flask(__name__)
@ -16,6 +19,21 @@ def create_app() -> Flask:
create_all_tables()
session = get_session()
area_service = CRUDService(_models.Area, session)
brand_service = CRUDService(_models.Brand, session)
device_type_service = CRUDService(_models.DeviceType, session)
image_service = CRUDService(_models.Image, session)
inventory_service = CRUDService(_models.Inventory, session)
room_function_service = CRUDService(_models.RoomFunction, session)
room_service = CRUDService(_models.Room, session)
user_service = CRUDService(_models.User, session)
work_log_service = CRUDService(_models.WorkLog, session)
work_note_service = CRUDService(_models.WorkNote, session)
app.register_blueprint(generate_crud_blueprint(_models.Area, area_service), url_prefix="/api/area")
@app.get("/")
def index():
return {"status": "ok"}

View file

@ -4,3 +4,19 @@ from sqlalchemy import Integer, Unicode
from sqlalchemy.orm import Mapped, mapped_column
from crudkit.core.base import Base, CRUDMixin
from .area import Area
from .brand import Brand
from .device_type import DeviceType
from .image import Image
from .inventory import Inventory
from .room_function import RoomFunction
from .room import Room
from .user import User
from .work_log import WorkLog
from .work_note import WorkNote
__all__ = [
"Area", "Brand", "DeviceType", "Image", "Inventory",
"RoomFunction", "Room", "User", "WorkLog", "WorkNote",
]

View file

@ -15,4 +15,4 @@ class Brand(Base, CRUDMixin):
is_deleted: Mapped[Boolean] = mapped_column(Boolean, nullable=False, default=False)
def __repr__(self) -> str:
return f"<Brand(id={self.id}, name={repr(self.name)})>"4
return f"<Brand(id={self.id}, name={repr(self.name)})>"

View file

@ -12,9 +12,9 @@ class Image(Base, CRUDMixin):
caption: Mapped[str] = mapped_column(Unicode(255), default="")
timestamp: Mapped[DateTime] = mapped_column(DateTime, default=func.now(), server_default=func.now())
inventory: Mapped[Optional['Inventory']] = relationship('Inventory', back_populates='images')
inventory: Mapped[Optional['Inventory']] = relationship('Inventory', back_populates='image')
user: Mapped[Optional['User']] = relationship('User', back_populates='image')
worklogs: Mapped[List['WorkLog']] = relationship('WorkLog', secondary=worklog_images, back_populates='images')
# worklogs: Mapped[List['WorkLog']] = relationship('WorkLog', back_populates='images')
def __repr__(self):
return f"<Image(id={self.id}, filename={self.filename})>"

View file

@ -1,4 +1,4 @@
from typing import Optional
from typing import List, Optional
from sqlalchemy import Boolean, DateTime, ForeignKey, Index, Integer, Unicode
from sqlalchemy.orm import Mapped, mapped_column, relationship
@ -15,11 +15,11 @@ class Inventory(Base, CRUDMixin):
condition: Mapped[str] = mapped_column(Unicode(255))
model: Mapped[Optional[str]] = mapped_column(Unicode(255))
notes: Mapped[Optional[str]] = mapped_column(Unicode(255))
shared = Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
shared: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
timestamp: Mapped[DateTime] = mapped_column(DateTime)
brand: Mapped[Optional['Brand']] = relationship('Brand', back_populates='inventory')
brand_id: Mapped[Optional[int]] = mapped_column(Integer, ForeignKey('users.id'), nullable=True, index=True)
brand_id: Mapped[Optional[int]] = mapped_column(Integer, ForeignKey('brand.id'), nullable=True, index=True)
device_type: Mapped[Optional['DeviceType']] = relationship('DeviceType', back_populates='inventory')
device_type_id: Mapped[Optional[int]] = mapped_column('type_id', Integer, ForeignKey("item.id"), nullable=True, index=True)
@ -27,12 +27,14 @@ class Inventory(Base, CRUDMixin):
image: Mapped[Optional['Image']] = relationship('Image', back_populates='inventory', passive_deletes=True)
image_id: Mapped[Optional[int]] = mapped_column(Integer, ForeignKey('images.id', ondelete='SET NULL'), nullable=True, index=True)
location = Mapped[Optional['Room']] = relationship('Room', back_populates='inventory')
location_id = Mapped[Optional[int]] = mapped_column(Integer, ForeignKey('rooms.id'), nullable=True, index=True)
location: Mapped[Optional['Room']] = relationship('Room', back_populates='inventory')
location_id: Mapped[Optional[int]] = mapped_column(Integer, ForeignKey('rooms.id'), nullable=True, index=True)
owner: Mapped[Optional['User']] = relationship('User', back_populates='inventory')
owner_id: Mapped[Optional[int]] = mapped_column(Integer, ForeignKey("users.id"), nullable=True, index=True)
work_logs: Mapped[Optional[List['WorkLog']]] = relationship('WorkLog', back_populates='work_item')
def __repr__(self):
parts = [f"id={self.id}"]

View file

@ -1,10 +1,13 @@
from typing import List, Optional
from typing import List, Optional, TYPE_CHECKING
from sqlalchemy import ForeignKey, Integer, Unicode
from sqlalchemy.orm import Mapped, mapped_column, relationship
from crudkit.core.base import Base, CRUDMixin
if TYPE_CHECKING:
from .user import User
class Room(Base, CRUDMixin):
__tablename__ = 'rooms'

View file

@ -1,10 +1,13 @@
from typing import List, Optional
from typing import List, Optional, TYPE_CHECKING
from sqlalchemy import Boolean, Integer, ForeignKey, Unicode
from sqlalchemy.orm import Mapped, mapped_column, relationship
from crudkit.core.base import Base, CRUDMixin
if TYPE_CHECKING:
from .room import Room
class User(Base, CRUDMixin):
__tablename__ = 'users'
@ -20,12 +23,14 @@ class User(Base, CRUDMixin):
inventory: Mapped[List['Inventory']] = relationship('Inventory', back_populates='owner')
location: Mapped[Optional['Room']] = relationship('Room', back_populates='owner')
location_id: Mapped[Optional[int]] = mapped_column(Integer, ForeignKey("users.id"), nullable=True, index=True)
location: Mapped[Optional['Room']] = relationship('Room', back_populates='users')
location_id: Mapped[Optional[int]] = mapped_column(Integer, ForeignKey("rooms.id"), nullable=True, index=True)
supervisor: Mapped[Optional['User']] = relationship('User', back_populates='subordinates')
supervisor_id: Mapped[Optional[int]] = mapped_column(Integer, ForeignKey("user.id"), nullable=True, index=True)
supervisor: Mapped[Optional['User']] = relationship('User', back_populates='subordinates', remote_side='User.id')
supervisor_id: Mapped[Optional[int]] = mapped_column(Integer, ForeignKey("users.id"), nullable=True, index=True)
subordinates: Mapped[List['User']] = relationship('User', back_populates='supervisor')
work_logs: Mapped[Optional[List['WorkLog']]] = relationship('WorkLog', back_populates='contact')
def __repr__(self):
return f"<User(id={self.id}, first_name={repr(self.first_name)}, last_name={repr(self.last_name)})>"

View file

@ -14,7 +14,7 @@ class WorkLog(Base, CRUDMixin):
complete: Mapped[Optional[bool]] = mapped_column(Boolean, nullable=False, default=False)
contact: Mapped[Optional['User']] = relationship('User', back_populates='work_logs')
contact_id: Mapped[Optional[int]] = mapped_column(Integer, ForeignKey("user.id"), nullable=True, index=True)
contact_id: Mapped[Optional[int]] = mapped_column(Integer, ForeignKey("users.id"), nullable=True, index=True)
updates: Mapped[List['WorkNote']] = relationship('WorkNote', back_populates='work_log', cascade='all, delete-orphan')

View file

@ -1,4 +1,4 @@
from sqlalchemy import DateTime, UnicodeText, func
from sqlalchemy import DateTime, ForeignKey, Integer, UnicodeText, func
from sqlalchemy.orm import Mapped, mapped_column, relationship
from crudkit.core.base import Base, CRUDMixin
@ -10,6 +10,7 @@ class WorkNote(Base, CRUDMixin):
timestamp: Mapped[DateTime] = mapped_column(DateTime, default=func.now(), server_default=func.now())
work_log: Mapped['WorkLog'] = relationship('WorkLog', back_populates='updates')
work_log_id: Mapped[int] = mapped_column(Integer, ForeignKey('work_log.id'))
def __repr__(self) -> str:
preview = self.content[:30].replace("\n", " ") + "..." if len(self.content) > 30 else self.content