Migrate from SQLAlchemy 1.x legacy Query API to 2.x style select/delete statements

This commit is contained in:
2026-04-06 01:06:01 +08:00
parent 356950e2c7
commit 970c2e9946
39 changed files with 372 additions and 275 deletions
+11 -11
View File
@@ -55,7 +55,7 @@ class SameCurrencyAsOriginalLineItems:
return
original_line_item_currency_codes: set[str] = set(db.session.scalars(
sa.select(JournalEntryLineItem.currency_code)
.filter(JournalEntryLineItem.id.in_(original_line_item_id))).all())
.where(JournalEntryLineItem.id.in_(original_line_item_id))).all())
for currency_code in original_line_item_currency_codes:
if field.data != currency_code:
raise ValidationError(lazy_gettext(
@@ -72,17 +72,17 @@ class KeepCurrencyWhenHavingOffset:
if field.data is None:
return
offset: sa.Alias = offset_alias()
original_line_items: list[JournalEntryLineItem]\
= JournalEntryLineItem.query\
original_line_items: list[JournalEntryLineItem] = db.session.scalars(
sa.select(JournalEntryLineItem)
.join(offset,
JournalEntryLineItem.id == offset.c.original_line_item_id,
isouter=True)\
.filter(JournalEntryLineItem.id
.in_({x.id.data for x in form.line_items
if x.id.data is not None}))\
isouter=True)
.where(JournalEntryLineItem.id
.in_({x.id.data for x in form.line_items
if x.id.data is not None}))
.group_by(JournalEntryLineItem.id,
JournalEntryLineItem.currency_code)\
.having(sa.func.count(offset.c.id) > 0).all()
JournalEntryLineItem.currency_code)
.having(sa.func.count(offset.c.id) > 0)).unique().all()
for original_line_item in original_line_items:
if original_line_item.currency_code != field.data:
raise ValidationError(lazy_gettext(
@@ -152,8 +152,8 @@ class CurrencyForm(FlaskForm):
line_item_id: set[int] = {x.id.data for x in line_item_forms
if x.id.data is not None}
select: sa.Select = sa.select(sa.func.count(JournalEntryLineItem.id))\
.filter(JournalEntryLineItem.original_line_item_id
.in_(line_item_id))
.where(JournalEntryLineItem.original_line_item_id
.in_(line_item_id))
return db.session.scalar(select) > 0
@@ -159,8 +159,9 @@ class JournalEntryForm(FlaskForm):
to_delete: set[int] = {x.id for x in obj.line_items
if x.id not in collector.to_keep}
if len(to_delete) > 0:
JournalEntryLineItem.query\
.filter(JournalEntryLineItem.id.in_(to_delete)).delete()
db.session.execute(
sa.delete(JournalEntryLineItem)
.where(JournalEntryLineItem.id.in_(to_delete)))
self.is_modified = True
if is_new or db.session.is_modified(obj):
@@ -195,7 +196,7 @@ class JournalEntryForm(FlaskForm):
if self.max_date is not None and new_date == self.max_date:
db_min_no: int | None = db.session.scalar(
sa.select(sa.func.min(JournalEntry.no))
.filter(JournalEntry.date == new_date))
.where(JournalEntry.date == new_date))
if db_min_no is None:
obj.date = new_date
obj.no = 1
@@ -205,8 +206,9 @@ class JournalEntryForm(FlaskForm):
sort_journal_entries_in(new_date)
else:
sort_journal_entries_in(new_date, obj.id)
count: int = JournalEntry.query\
.filter(JournalEntry.date == new_date).count()
count: int = db.session.scalar(
sa.select(sa.func.count(JournalEntry.id))
.where(JournalEntry.date == new_date))
obj.date = new_date
obj.no = count + 1
@@ -221,7 +223,7 @@ class JournalEntryForm(FlaskForm):
if not (x.code[0] == "2" and x.is_need_offset)]
in_use: set[int] = set(db.session.scalars(
sa.select(JournalEntryLineItem.account_id)
.filter(JournalEntryLineItem.is_debit)
.where(JournalEntryLineItem.is_debit)
.group_by(JournalEntryLineItem.account_id)).all())
for account in accounts:
account.is_in_use = account.id in in_use
@@ -238,7 +240,7 @@ class JournalEntryForm(FlaskForm):
if not (x.code[0] == "1" and x.is_need_offset)]
in_use: set[int] = set(db.session.scalars(
sa.select(JournalEntryLineItem.account_id)
.filter(sa.not_(JournalEntryLineItem.is_debit))
.where(sa.not_(JournalEntryLineItem.is_debit))
.group_by(JournalEntryLineItem.account_id)).all())
for account in accounts:
account.is_in_use = account.id in in_use
@@ -288,7 +290,7 @@ class JournalEntryForm(FlaskForm):
return None
select: sa.Select = sa.select(sa.func.max(JournalEntry.date))\
.join(JournalEntryLineItem)\
.filter(JournalEntryLineItem.id.in_(original_line_item_id))
.where(JournalEntryLineItem.id.in_(original_line_item_id))
return db.session.scalar(select)
@property
@@ -301,8 +303,8 @@ class JournalEntryForm(FlaskForm):
if x.id.data is not None}
select: sa.Select = sa.select(sa.func.min(JournalEntry.date))\
.join(JournalEntryLineItem)\
.filter(JournalEntryLineItem.original_line_item_id
.in_(line_item_id))
.where(JournalEntryLineItem.original_line_item_id
.in_(line_item_id))
return db.session.scalar(select)
@@ -202,9 +202,9 @@ class NotExceedingOriginalLineItemNetBalance:
else_=-JournalEntryLineItem.amount))
offset_total_but_form: Decimal | None = db.session.scalar(
sa.select(offset_total_func)
.filter(JournalEntryLineItem.original_line_item_id
== original_line_item.id,
JournalEntryLineItem.id.not_in(existing_line_item_id)))
.where(JournalEntryLineItem.original_line_item_id
== original_line_item.id,
JournalEntryLineItem.id.not_in(existing_line_item_id)))
if offset_total_but_form is None:
offset_total_but_form = Decimal("0")
offset_total_on_form: Decimal = sum(
@@ -231,7 +231,7 @@ class NotLessThanOffsetTotal:
(JournalEntryLineItem.is_debit != is_debit,
JournalEntryLineItem.amount),
else_=-JournalEntryLineItem.amount)))\
.filter(JournalEntryLineItem.original_line_item_id == form.id.data)
.where(JournalEntryLineItem.original_line_item_id == form.id.data)
offset_total: Decimal | None = db.session.scalar(select_offset_total)
if offset_total is not None and field.data < offset_total:
raise ValidationError(lazy_gettext(
@@ -353,13 +353,14 @@ class LineItemForm(FlaskForm):
def get_offsets() -> list[JournalEntryLineItem]:
if not self.is_need_offset or self.id.data is None:
return []
return JournalEntryLineItem.query.join(JournalEntry)\
.filter(JournalEntryLineItem.original_line_item_id
== self.id.data)\
return db.session.scalars(
sa.select(JournalEntryLineItem).join(JournalEntry)
.where(JournalEntryLineItem.original_line_item_id
== self.id.data)
.order_by(JournalEntry.date, JournalEntry.no,
JournalEntryLineItem.no)\
JournalEntryLineItem.no)
.options(selectinload(JournalEntryLineItem.journal_entry),
selectinload(JournalEntryLineItem.account)).all()
selectinload(JournalEntryLineItem.account))).all()
setattr(self, "__offsets", get_offsets())
return getattr(self, "__offsets")
@@ -37,9 +37,9 @@ def sort_journal_entries_in(date: dt.date, exclude: int | None = None) -> None:
conditions: list[sa.ColumnElement[bool]] = [JournalEntry.date == date]
if exclude is not None:
conditions.append(JournalEntry.id != exclude)
journal_entries: list[JournalEntry] = JournalEntry.query\
.filter(*conditions)\
.order_by(JournalEntry.no).all()
journal_entries: list[JournalEntry] = db.session.scalars(
sa.select(JournalEntry).where(*conditions)
.order_by(JournalEntry.no)).all()
for i in range(len(journal_entries)):
if journal_entries[i].no != i + 1:
journal_entries[i].no = i + 1
@@ -63,8 +63,9 @@ class JournalEntryReorderForm:
:return:
"""
journal_entries: list[JournalEntry] = JournalEntry.query\
.filter(JournalEntry.date == self.date).all()
journal_entries: list[JournalEntry] = db.session.scalars(
sa.select(JournalEntry)
.where(JournalEntry.date == self.date)).all()
# Collects the specified order.
orders: dict[JournalEntry, int] = {}
@@ -272,15 +272,17 @@ class DescriptionEditor:
select: sa.Select = sa.Select(debit_credit, tag_type, tag,
JournalEntryLineItem.account_id,
sa.func.count().label("freq"))\
.filter(JournalEntryLineItem.description.is_not(None),
JournalEntryLineItem.description.like("_%—_%"),
JournalEntryLineItem.original_line_item_id.is_(None))\
.where(JournalEntryLineItem.description.is_not(None),
JournalEntryLineItem.description.like("_%—_%"),
JournalEntryLineItem.original_line_item_id.is_(None))\
.group_by(debit_credit, tag_type, tag,
JournalEntryLineItem.account_id)
result: list[sa.Row] = db.session.execute(select).all()
accounts: dict[int, Account] \
= {x.id: x for x in Account.query
.filter(Account.id.in_({x.account_id for x in result})).all()}
= {x.id: x for x in db.session.scalars(
sa.select(Account)
.where(Account.id.in_({x.account_id for x in result})))
.unique()}
debit_credit_dict: dict[Literal["debit", "credit"],
DescriptionDebitCredit] \
= {x.debit_credit: x for x in {self.debit, self.credit}}
@@ -326,7 +328,8 @@ class DescriptionEditor:
= [get_condition(x) for x in codes]
accounts: dict[str, Account] \
= {x.code: x for x in
Account.query.filter(sa.or_(*conditions)).all()}
db.session.scalars(
sa.select(Account).where(sa.or_(*conditions))).unique()}
for code in codes:
assert code in accounts, \
f"Unknown account \"{code}\" for regular transactions."
@@ -61,20 +61,21 @@ def get_selectable_original_line_items(
.join(offset,
JournalEntryLineItem.id == offset.c.original_line_item_id,
isouter=True)\
.filter(*conditions)\
.where(*conditions)\
.group_by(JournalEntryLineItem.id)\
.having(sa.or_(sa.func.count(offset.c.id) == 0, net_balance != 0))
net_balances: dict[int, Decimal] \
= {x.id: x.net_balance
for x in db.session.execute(select_net_balances).all()}
line_items: list[JournalEntryLineItem] = JournalEntryLineItem.query\
.filter(JournalEntryLineItem.id.in_({x for x in net_balances}))\
.join(JournalEntry)\
for x in db.session.execute(select_net_balances)}
line_items: list[JournalEntryLineItem] = db.session.scalars(
sa.select(JournalEntryLineItem)
.where(JournalEntryLineItem.id.in_({x for x in net_balances}))
.join(JournalEntry)
.order_by(JournalEntry.date, JournalEntry.no,
JournalEntryLineItem.is_debit, JournalEntryLineItem.no)\
JournalEntryLineItem.is_debit, JournalEntryLineItem.no)
.options(selectinload(JournalEntryLineItem.currency),
selectinload(JournalEntryLineItem.account),
selectinload(JournalEntryLineItem.journal_entry)).all()
selectinload(JournalEntryLineItem.journal_entry))).all()
line_items.reverse()
for line_item in line_items:
line_item.net_balance = line_item.amount \
+3 -3
View File
@@ -195,9 +195,9 @@ def show_journal_entry_order(date: dt.date) -> str:
:param date: The date.
:return: The order of the journal entries in the date.
"""
journal_entries: list[JournalEntry] = JournalEntry.query \
.filter(JournalEntry.date == date) \
.order_by(JournalEntry.no).all()
journal_entries: list[JournalEntry] = db.session.scalars(
sa.select(JournalEntry).where(JournalEntry.date == date)
.order_by(JournalEntry.no)).all()
return render_template("accounting/journal-entry/order.html",
date=date, list=journal_entries)