Rewrote the data model declaration with the mapped type hint and the mapped columns in SQLAlchemy 2.0. Added "SQLAlchemy >= 2" to the dependencies.

This commit is contained in:
依瑪貓 2023-04-23 11:54:37 +08:00
parent eed4c923f6
commit 3f7e4c0dda
2 changed files with 125 additions and 138 deletions

View File

@ -34,6 +34,7 @@ classifiers = [
] ]
dependencies = [ dependencies = [
"flask", "flask",
"SQLAlchemy >= 2",
"Flask-SQLAlchemy", "Flask-SQLAlchemy",
"Flask-WTF", "Flask-WTF",
"Flask-Babel >= 3", "Flask-Babel >= 3",

View File

@ -19,6 +19,7 @@
""" """
from __future__ import annotations from __future__ import annotations
import datetime as dt
import re import re
import typing as t import typing as t
from decimal import Decimal from decimal import Decimal
@ -27,6 +28,7 @@ import sqlalchemy as sa
from babel import Locale from babel import Locale
from flask_babel import get_locale, get_babel from flask_babel import get_locale, get_babel
from sqlalchemy import text from sqlalchemy import text
from sqlalchemy.orm import Mapped, mapped_column
from accounting import db from accounting import db
from accounting.locale import gettext from accounting.locale import gettext
@ -37,14 +39,14 @@ class BaseAccount(db.Model):
"""A base account.""" """A base account."""
__tablename__ = "accounting_base_accounts" __tablename__ = "accounting_base_accounts"
"""The table name.""" """The table name."""
code = db.Column(db.String, nullable=False, primary_key=True) code: Mapped[str] = mapped_column(primary_key=True)
"""The code.""" """The code."""
title_l10n = db.Column("title", db.String, nullable=False) title_l10n: Mapped[str] = mapped_column("title")
"""The title.""" """The title."""
l10n = db.relationship("BaseAccountL10n", back_populates="account", l10n: Mapped[list[BaseAccountL10n]] \
lazy=False) = db.relationship(back_populates="account", lazy=False)
"""The localized titles.""" """The localized titles."""
accounts = db.relationship("Account", back_populates="base") accounts: Mapped[list[Account]] = db.relationship(back_populates="base")
"""The descendant accounts under the base account.""" """The descendant accounts under the base account."""
def __str__(self) -> str: def __str__(self) -> str:
@ -81,17 +83,16 @@ class BaseAccountL10n(db.Model):
"""A localized base account title.""" """A localized base account title."""
__tablename__ = "accounting_base_accounts_l10n" __tablename__ = "accounting_base_accounts_l10n"
"""The table name.""" """The table name."""
account_code = db.Column(db.String, account_code: Mapped[str] \
db.ForeignKey(BaseAccount.code, = mapped_column(db.ForeignKey(BaseAccount.code, onupdate="CASCADE",
onupdate="CASCADE",
ondelete="CASCADE"), ondelete="CASCADE"),
nullable=False, primary_key=True) primary_key=True)
"""The code of the account.""" """The code of the account."""
account = db.relationship(BaseAccount, back_populates="l10n") account: Mapped[BaseAccount] = db.relationship(back_populates="l10n")
"""The account.""" """The account."""
locale = db.Column(db.String, nullable=False, primary_key=True) locale: Mapped[str] = mapped_column(primary_key=True)
"""The locale.""" """The locale."""
title = db.Column(db.String, nullable=False) title: Mapped[str]
"""The localized title.""" """The localized title."""
@ -99,47 +100,43 @@ class Account(db.Model):
"""An account.""" """An account."""
__tablename__ = "accounting_accounts" __tablename__ = "accounting_accounts"
"""The table name.""" """The table name."""
id = db.Column(db.Integer, nullable=False, primary_key=True, id: Mapped[int] = mapped_column(primary_key=True, autoincrement=False)
autoincrement=False)
"""The account ID.""" """The account ID."""
base_code = db.Column(db.String, base_code: Mapped[str] \
db.ForeignKey(BaseAccount.code, onupdate="CASCADE", = mapped_column(db.ForeignKey(BaseAccount.code, onupdate="CASCADE",
ondelete="CASCADE"), ondelete="CASCADE"))
nullable=False)
"""The code of the base account.""" """The code of the base account."""
base = db.relationship(BaseAccount, back_populates="accounts") base: Mapped[BaseAccount] = db.relationship(back_populates="accounts")
"""The base account.""" """The base account."""
no = db.Column(db.Integer, nullable=False, default=text("1")) no: Mapped[int] = mapped_column(default=text("1"))
"""The account number under the base account.""" """The account number under the base account."""
title_l10n = db.Column("title", db.String, nullable=False) title_l10n: Mapped[str] = mapped_column("title")
"""The title.""" """The title."""
is_need_offset = db.Column(db.Boolean, nullable=False, default=False) is_need_offset: Mapped[bool] = mapped_column(default=False)
"""Whether the journal entry line items of this account need offset.""" """Whether the journal entry line items of this account need offset."""
created_at = db.Column(db.DateTime(timezone=True), nullable=False, created_at: Mapped[dt.datetime] \
= mapped_column(db.DateTime(timezone=True),
server_default=db.func.now()) server_default=db.func.now())
"""The time of creation.""" """The time of creation."""
created_by_id = db.Column(db.Integer, created_by_id: Mapped[int] \
db.ForeignKey(user_pk_column, = mapped_column(db.ForeignKey(user_pk_column, onupdate="CASCADE"))
onupdate="CASCADE"),
nullable=False)
"""The ID of the creator.""" """The ID of the creator."""
created_by = db.relationship(user_cls, foreign_keys=created_by_id) created_by: Mapped[user_cls] = db.relationship(foreign_keys=created_by_id)
"""The creator.""" """The creator."""
updated_at = db.Column(db.DateTime(timezone=True), nullable=False, updated_at: Mapped[dt.datetime] \
= mapped_column(db.DateTime(timezone=True),
server_default=db.func.now()) server_default=db.func.now())
"""The time of last update.""" """The time of last update."""
updated_by_id = db.Column(db.Integer, updated_by_id: Mapped[int] \
db.ForeignKey(user_pk_column, = mapped_column(db.ForeignKey(user_pk_column, onupdate="CASCADE"))
onupdate="CASCADE"),
nullable=False)
"""The ID of the updator.""" """The ID of the updator."""
updated_by = db.relationship(user_cls, foreign_keys=updated_by_id) updated_by: Mapped[user_cls] = db.relationship(foreign_keys=updated_by_id)
"""The updator.""" """The updator."""
l10n = db.relationship("AccountL10n", back_populates="account", l10n: Mapped[list[AccountL10n]] \
lazy=False) = db.relationship(back_populates="account", lazy=False)
"""The localized titles.""" """The localized titles."""
line_items = db.relationship("JournalEntryLineItem", line_items: Mapped[list[JournalEntryLineItem]] \
back_populates="account") = db.relationship(back_populates="account")
"""The journal entry line items.""" """The journal entry line items."""
CASH_CODE: str = "1111-001" CASH_CODE: str = "1111-001"
@ -352,16 +349,16 @@ class AccountL10n(db.Model):
"""A localized account title.""" """A localized account title."""
__tablename__ = "accounting_accounts_l10n" __tablename__ = "accounting_accounts_l10n"
"""The table name.""" """The table name."""
account_id = db.Column(db.Integer, account_id: Mapped[int] \
db.ForeignKey(Account.id, onupdate="CASCADE", = mapped_column(db.ForeignKey(Account.id, onupdate="CASCADE",
ondelete="CASCADE"), ondelete="CASCADE"),
nullable=False, primary_key=True) primary_key=True)
"""The account ID.""" """The account ID."""
account = db.relationship(Account, back_populates="l10n") account: Mapped[Account] = db.relationship(back_populates="l10n")
"""The account.""" """The account."""
locale = db.Column(db.String, nullable=False, primary_key=True) locale: Mapped[str] = mapped_column(primary_key=True)
"""The locale.""" """The locale."""
title = db.Column(db.String, nullable=False) title: Mapped[str]
"""The localized title.""" """The localized title."""
@ -369,35 +366,34 @@ class Currency(db.Model):
"""A currency.""" """A currency."""
__tablename__ = "accounting_currencies" __tablename__ = "accounting_currencies"
"""The table name.""" """The table name."""
code = db.Column(db.String, nullable=False, primary_key=True) code: Mapped[str] = mapped_column(primary_key=True)
"""The code.""" """The code."""
name_l10n = db.Column("name", db.String, nullable=False) name_l10n: Mapped[str] = mapped_column("name")
"""The name.""" """The name."""
created_at = db.Column(db.DateTime(timezone=True), nullable=False, created_at: Mapped[dt.datetime] \
= mapped_column(db.DateTime(timezone=True),
server_default=db.func.now()) server_default=db.func.now())
"""The time of creation.""" """The time of creation."""
created_by_id = db.Column(db.Integer, created_by_id: Mapped[int] \
db.ForeignKey(user_pk_column, = mapped_column(db.ForeignKey(user_pk_column, onupdate="CASCADE"))
onupdate="CASCADE"),
nullable=False)
"""The ID of the creator.""" """The ID of the creator."""
created_by = db.relationship(user_cls, foreign_keys=created_by_id) created_by: Mapped[user_cls] = db.relationship(foreign_keys=created_by_id)
"""The creator.""" """The creator."""
updated_at = db.Column(db.DateTime(timezone=True), nullable=False, updated_at: Mapped[dt.datetime] \
= mapped_column(db.DateTime(timezone=True),
server_default=db.func.now()) server_default=db.func.now())
"""The time of last update.""" """The time of last update."""
updated_by_id = db.Column(db.Integer, updated_by_id: Mapped[int] \
db.ForeignKey(user_pk_column, = mapped_column(db.ForeignKey(user_pk_column, onupdate="CASCADE"))
onupdate="CASCADE"),
nullable=False)
"""The ID of the updator.""" """The ID of the updator."""
updated_by = db.relationship(user_cls, foreign_keys=updated_by_id) updated_by: Mapped[user_cls] \
= db.relationship(foreign_keys=updated_by_id)
"""The updator.""" """The updator."""
l10n = db.relationship("CurrencyL10n", back_populates="currency", l10n: Mapped[list[CurrencyL10n]] \
lazy=False) = db.relationship(back_populates="currency", lazy=False)
"""The localized names.""" """The localized names."""
line_items = db.relationship("JournalEntryLineItem", line_items: Mapped[list[JournalEntryLineItem]] \
back_populates="currency") = db.relationship(back_populates="currency")
"""The journal entry line items.""" """The journal entry line items."""
def __str__(self) -> str: def __str__(self) -> str:
@ -479,16 +475,16 @@ class CurrencyL10n(db.Model):
"""A localized currency name.""" """A localized currency name."""
__tablename__ = "accounting_currencies_l10n" __tablename__ = "accounting_currencies_l10n"
"""The table name.""" """The table name."""
currency_code = db.Column(db.String, currency_code: Mapped[str] \
db.ForeignKey(Currency.code, onupdate="CASCADE", = mapped_column(db.ForeignKey(Currency.code, onupdate="CASCADE",
ondelete="CASCADE"), ondelete="CASCADE"),
nullable=False, primary_key=True) primary_key=True)
"""The currency code.""" """The currency code."""
currency = db.relationship(Currency, back_populates="l10n") currency: Mapped[Currency] = db.relationship(back_populates="l10n")
"""The currency.""" """The currency."""
locale = db.Column(db.String, nullable=False, primary_key=True) locale: Mapped[str] = mapped_column(primary_key=True)
"""The locale.""" """The locale."""
name = db.Column(db.String, nullable=False) name: Mapped[str]
"""The localized name.""" """The localized name."""
@ -539,37 +535,34 @@ class JournalEntry(db.Model):
"""A journal entry.""" """A journal entry."""
__tablename__ = "accounting_journal_entries" __tablename__ = "accounting_journal_entries"
"""The table name.""" """The table name."""
id = db.Column(db.Integer, nullable=False, primary_key=True, id: Mapped[int] = mapped_column(primary_key=True, autoincrement=False)
autoincrement=False)
"""The journal entry ID.""" """The journal entry ID."""
date = db.Column(db.Date, nullable=False) date: Mapped[dt.date]
"""The date.""" """The date."""
no = db.Column(db.Integer, nullable=False, default=text("1")) no: Mapped[int] = mapped_column(default=text("1"))
"""The account number under the date.""" """The account number under the date."""
note = db.Column(db.String) note: Mapped[str | None]
"""The note.""" """The note."""
created_at = db.Column(db.DateTime(timezone=True), nullable=False, created_at: Mapped[dt.datetime] \
= mapped_column(db.DateTime(timezone=True),
server_default=db.func.now()) server_default=db.func.now())
"""The time of creation.""" """The time of creation."""
created_by_id = db.Column(db.Integer, created_by_id: Mapped[int] \
db.ForeignKey(user_pk_column, = mapped_column(db.ForeignKey(user_pk_column, onupdate="CASCADE"))
onupdate="CASCADE"),
nullable=False)
"""The ID of the creator.""" """The ID of the creator."""
created_by = db.relationship(user_cls, foreign_keys=created_by_id) created_by: Mapped[user_cls] = db.relationship(foreign_keys=created_by_id)
"""The creator.""" """The creator."""
updated_at = db.Column(db.DateTime(timezone=True), nullable=False, updated_at: Mapped[dt.datetime] \
= mapped_column(db.DateTime(timezone=True),
server_default=db.func.now()) server_default=db.func.now())
"""The time of last update.""" """The time of last update."""
updated_by_id = db.Column(db.Integer, updated_by_id: Mapped[int] \
db.ForeignKey(user_pk_column, = mapped_column(db.ForeignKey(user_pk_column, onupdate="CASCADE"))
onupdate="CASCADE"),
nullable=False)
"""The ID of the updator.""" """The ID of the updator."""
updated_by = db.relationship(user_cls, foreign_keys=updated_by_id) updated_by: Mapped[user_cls] = db.relationship(foreign_keys=updated_by_id)
"""The updator.""" """The updator."""
line_items = db.relationship("JournalEntryLineItem", line_items: Mapped[list[JournalEntryLineItem]] \
back_populates="journal_entry") = db.relationship(back_populates="journal_entry")
"""The line items.""" """The line items."""
def __str__(self) -> str: def __str__(self) -> str:
@ -659,44 +652,39 @@ class JournalEntryLineItem(db.Model):
"""A line item in the journal entry.""" """A line item in the journal entry."""
__tablename__ = "accounting_journal_entry_line_items" __tablename__ = "accounting_journal_entry_line_items"
"""The table name.""" """The table name."""
id = db.Column(db.Integer, nullable=False, primary_key=True, id: Mapped[int] = mapped_column(primary_key=True, autoincrement=False)
autoincrement=False)
"""The line item ID.""" """The line item ID."""
journal_entry_id = db.Column(db.Integer, journal_entry_id: Mapped[int] \
db.ForeignKey(JournalEntry.id, = mapped_column(db.ForeignKey(JournalEntry.id, onupdate="CASCADE",
onupdate="CASCADE", ondelete="CASCADE"))
ondelete="CASCADE"),
nullable=False)
"""The journal entry ID.""" """The journal entry ID."""
journal_entry = db.relationship(JournalEntry, back_populates="line_items") journal_entry: Mapped[JournalEntry] \
= db.relationship(back_populates="line_items")
"""The journal entry.""" """The journal entry."""
is_debit = db.Column(db.Boolean, nullable=False) is_debit: Mapped[bool]
"""True for a debit line item, or False for a credit line item.""" """True for a debit line item, or False for a credit line item."""
no = db.Column(db.Integer, nullable=False) no: Mapped[int]
"""The line item number under the journal entry and debit or credit.""" """The line item number under the journal entry and debit or credit."""
original_line_item_id = db.Column(db.Integer, original_line_item_id: Mapped[int | None] \
db.ForeignKey(id, onupdate="CASCADE"), = mapped_column(db.ForeignKey(id, onupdate="CASCADE"))
nullable=True)
"""The ID of the original line item.""" """The ID of the original line item."""
original_line_item = db.relationship("JournalEntryLineItem", original_line_item: Mapped[JournalEntryLineItem | None] \
remote_side=id, passive_deletes=True) = db.relationship(remote_side=id, passive_deletes=True)
"""The original line item.""" """The original line item."""
currency_code = db.Column(db.String, currency_code: Mapped[str] \
db.ForeignKey(Currency.code, onupdate="CASCADE"), = mapped_column(db.ForeignKey(Currency.code, onupdate="CASCADE"))
nullable=False)
"""The currency code.""" """The currency code."""
currency = db.relationship(Currency, back_populates="line_items") currency: Mapped[Currency] = db.relationship(back_populates="line_items")
"""The currency.""" """The currency."""
account_id = db.Column(db.Integer, account_id: Mapped[int] \
db.ForeignKey(Account.id, = mapped_column(db.ForeignKey(Account.id, onupdate="CASCADE"))
onupdate="CASCADE"),
nullable=False)
"""The account ID.""" """The account ID."""
account = db.relationship(Account, back_populates="line_items", lazy=False) account: Mapped[Account] \
= db.relationship(back_populates="line_items", lazy=False)
"""The account.""" """The account."""
description = db.Column(db.String, nullable=True) description: Mapped[str | None]
"""The description.""" """The description."""
amount = db.Column(db.Numeric(14, 2), nullable=False) amount: Mapped[Decimal] = mapped_column(db.Numeric(14, 2))
"""The amount.""" """The amount."""
def __str__(self) -> str: def __str__(self) -> str:
@ -891,27 +879,25 @@ class Option(db.Model):
"""An option.""" """An option."""
__tablename__ = "accounting_options" __tablename__ = "accounting_options"
"""The table name.""" """The table name."""
name = db.Column(db.String, nullable=False, primary_key=True) name: Mapped[str] = mapped_column(primary_key=True)
"""The name.""" """The name."""
value = db.Column(db.Text, nullable=False) value: Mapped[str] = mapped_column(db.Text)
"""The option value.""" """The option value."""
created_at = db.Column(db.DateTime(timezone=True), nullable=False, created_at: Mapped[dt.datetime] \
= mapped_column(db.DateTime(timezone=True),
server_default=db.func.now()) server_default=db.func.now())
"""The time of creation.""" """The time of creation."""
created_by_id = db.Column(db.Integer, created_by_id: Mapped[int] \
db.ForeignKey(user_pk_column, = mapped_column(db.ForeignKey(user_pk_column, onupdate="CASCADE"))
onupdate="CASCADE"),
nullable=False)
"""The ID of the creator.""" """The ID of the creator."""
created_by = db.relationship(user_cls, foreign_keys=created_by_id) created_by: Mapped[user_cls] = db.relationship(foreign_keys=created_by_id)
"""The creator.""" """The creator."""
updated_at = db.Column(db.DateTime(timezone=True), nullable=False, updated_at: Mapped[dt.datetime] \
= mapped_column(db.DateTime(timezone=True),
server_default=db.func.now()) server_default=db.func.now())
"""The time of last update.""" """The time of last update."""
updated_by_id = db.Column(db.Integer, updated_by_id: Mapped[int] \
db.ForeignKey(user_pk_column, = mapped_column(db.ForeignKey(user_pk_column, onupdate="CASCADE"))
onupdate="CASCADE"),
nullable=False)
"""The ID of the updator.""" """The ID of the updator."""
updated_by = db.relationship(user_cls, foreign_keys=updated_by_id) updated_by: Mapped[user_cls] = db.relationship(foreign_keys=updated_by_id)
"""The updator.""" """The updator."""