1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
|
from typing import List
import datetime
from flask_login import UserMixin
from sqlalchemy import Column, Float, Integer, String, ForeignKey, Text
from sqlalchemy.orm import Mapped, mapped_column, relationship
from .auth.password import PasswordHash, Password
from . import db
user_category = db.Table(
"user_category_map",
Column("user_id", Integer, ForeignKey("user.id"), primary_key=True),
Column("category_id", Integer, ForeignKey("category.id"), primary_key=True),
)
class User(db.Model, UserMixin):
"""The table for Username and Password"""
id: Mapped[int] = mapped_column(primary_key=True, init=False)
name: Mapped[str] = mapped_column(String(64), unique=True, comment="The username")
password: Mapped[PasswordHash] = mapped_column(Password(), comment="The password as a hash")
expenses: Mapped[List["Expense"]] = relationship(
back_populates="user",
order_by="Expense.date",
cascade="all, delete",
init=False,
)
categories: Mapped[List["Category"]] = relationship(
secondary=user_category, init=False
)
class Category(db.Model):
"""The List of categories, contains both user defined and predefined"""
id: Mapped[int] = mapped_column(primary_key=True, init=False)
name: Mapped[str] = mapped_column(String(256), nullable=False, unique=True)
class Expense(db.Model):
"""The list of expenses"""
id: Mapped[int] = mapped_column(primary_key=True, init=False)
user_id: Mapped[int] = mapped_column(ForeignKey("user.id"), init=False)
user = relationship(User, back_populates="expenses")
date: Mapped[datetime.date] = mapped_column()
amount: Mapped[float] = mapped_column(Float(2))
category_id: Mapped[int] = mapped_column(ForeignKey("category.id"), init=False)
category: Mapped[Category] = relationship(cascade="all, delete")
description: Mapped[str] = mapped_column(Text(), default="")
def populate_table() -> None:
"""
Create the initial entries for the table.
Currently populates the Category table with predefined values
"""
for cat in ["Misc", "Income"]:
if db.session.scalars(
db.select(Category).where(Category.name == cat)
).one_or_none():
continue
db.session.add(Category(name=cat)) # type: ignore
db.session.commit()
|