Implement BaseModel class, TimestampMixin, TzDateTime type; cleanup Task model
This commit is contained in:
parent
7ce43a2bfe
commit
252c15acbd
15 changed files with 223 additions and 42 deletions
|
|
@ -1,5 +1,5 @@
|
|||
# Base model first
|
||||
from .base import metadata, BaseModel
|
||||
from .base import BaseModel
|
||||
|
||||
# Data models
|
||||
from .task import Task
|
||||
|
|
|
|||
|
|
@ -1,22 +1,62 @@
|
|||
from sqlalchemy import MetaData
|
||||
from sqlalchemy.orm import declarative_base
|
||||
from typing import Any, Iterable, Optional
|
||||
|
||||
from sqlalchemy import Column, Integer, inspect
|
||||
from sqlalchemy.orm import InstanceState, as_declarative
|
||||
|
||||
from tofu_api.common.database import Col, MetaData
|
||||
|
||||
__all__ = [
|
||||
'metadata',
|
||||
'BaseModel',
|
||||
]
|
||||
|
||||
# Define naming convention for constraints
|
||||
_naming_convention = {
|
||||
"ix": 'ix_%(column_0_label)s',
|
||||
"uq": "uq_%(table_name)s_%(column_0_name)s",
|
||||
"ck": "ck_%(table_name)s_%(constraint_name)s",
|
||||
"fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s",
|
||||
"pk": "pk_%(table_name)s"
|
||||
}
|
||||
|
||||
# Create metadata object for database schemas
|
||||
metadata = MetaData(naming_convention=_naming_convention)
|
||||
@as_declarative(name='BaseModel', metadata=MetaData())
|
||||
class BaseModel:
|
||||
"""
|
||||
Declarative base class for database models.
|
||||
"""
|
||||
|
||||
# Generate declarative base class for database models
|
||||
BaseModel = declarative_base(name='BaseModel', metadata=metadata)
|
||||
# Default primary key
|
||||
id: Col[int] = Column(Integer, nullable=False, primary_key=True)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
"""
|
||||
Return a string representation of this object.
|
||||
"""
|
||||
return self._repr(id=self.id) if hasattr(self, 'id') else self._repr()
|
||||
|
||||
def _repr(self, **fields) -> str:
|
||||
"""
|
||||
Helper method for implementing __repr__.
|
||||
"""
|
||||
state: InstanceState = inspect(self)
|
||||
state_str = f' [transient {id(self)}]' if state.transient \
|
||||
else f' [pending {id(self)}]' if state.pending \
|
||||
else ' [deleted]' if state.deleted \
|
||||
else ' [detached]' if state.detached else ''
|
||||
param_str = ', '.join([f'{key}={value!r}' for key, value in fields.items()] if fields else state.identity or [])
|
||||
return f'<{type(self).__name__}({param_str}){state_str}>'
|
||||
|
||||
def to_dict(
|
||||
self,
|
||||
*,
|
||||
fields: Optional[Iterable[str]] = None,
|
||||
exclude: Optional[Iterable[str]] = None,
|
||||
) -> dict[str, Any]:
|
||||
"""
|
||||
Return the object's data as a dictionary.
|
||||
|
||||
By default, the dictionary will contain all table columns (with their column name as key) defined in the model. This can be
|
||||
overridden by setting the `fields` and/or `exclude` parameters, in which case only fields that are listed in `fields` will be
|
||||
included in the dictionary, except for fields listed in `exclude`.
|
||||
"""
|
||||
# Determine fields to include in dictionary (starting will all table columns)
|
||||
included_fields = set(column.name for column in self.__table__.columns)
|
||||
if fields is not None:
|
||||
included_fields.intersection_update(fields)
|
||||
if exclude is not None:
|
||||
included_fields.difference_update(exclude)
|
||||
|
||||
return {
|
||||
field: getattr(self, field) for field in included_fields
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,25 +1,19 @@
|
|||
from sqlalchemy import Column, Integer, String, Text
|
||||
from sqlalchemy import Column, String, Text
|
||||
|
||||
from tofu_api.common.database import Col
|
||||
from tofu_api.common.database.mixins import TimestampMixin
|
||||
from .base import BaseModel
|
||||
|
||||
|
||||
class Task(BaseModel):
|
||||
class Task(TimestampMixin, BaseModel):
|
||||
"""
|
||||
Database model for tasks.
|
||||
"""
|
||||
|
||||
__tablename__ = 'tasks'
|
||||
__tablename__ = 'task'
|
||||
|
||||
id: int = Column(Integer, nullable=False, primary_key=True)
|
||||
# TODO: created_at, modified_at
|
||||
title: Col[str] = Column(String(255), nullable=False)
|
||||
description: Col[str] = Column(Text, nullable=False, default='')
|
||||
|
||||
title: str = Column(String(255), nullable=False)
|
||||
description: str = Column(Text, nullable=False, default='')
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
# TODO: Implement a generic to_dict() in the base model
|
||||
return {
|
||||
'id': self.id,
|
||||
'title': self.title,
|
||||
'description': self.description,
|
||||
}
|
||||
def __repr__(self):
|
||||
return self._repr(id=self.id, title=self.title)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue