Skip to content

Commit 1741a8c

Browse files
committed
Začetek ORM in spremembe modela na predavanjih
1 parent 3ed7491 commit 1741a8c

File tree

6 files changed

+4153
-19
lines changed

6 files changed

+4153
-19
lines changed

predavanja/primeri/banka/model.py

Lines changed: 39 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,52 @@
1+
from auth import auth
12
from dataclasses import dataclass
23
from datetime import datetime
3-
4+
from orm import povezi, stolpec, Entiteta, Funkcija
45

56
@dataclass
6-
class Kraj:
7-
posta: int
8-
kraj: str
7+
class Kraj(Entiteta):
8+
posta: int = stolpec(glavni_kljuc=True)
9+
kraj: str = stolpec(obvezen=True)
910

1011

1112
@dataclass
12-
class Oseba:
13-
emso: str
14-
ime: str
15-
priimek: str
16-
naslov: str
17-
kraj: Kraj
13+
class Oseba(Entiteta):
14+
emso: str = stolpec(glavni_kljuc=True)
15+
ime: str = stolpec(obvezen=True)
16+
priimek: str = stolpec(obvezen=True)
17+
naslov: str = stolpec(obvezen=True)
18+
kraj: Kraj = stolpec(obvezen=True)
1819

1920

2021
@dataclass
21-
class Racun:
22-
stevilka: int
23-
lastnik: Oseba
22+
class Racun(Entiteta):
23+
stevilka: int = stolpec(glavni_kljuc=True, stevec=True)
24+
lastnik: Oseba = stolpec(obvezen=True)
2425

2526

2627
@dataclass
27-
class Transakcija:
28-
id: int
29-
racun: Racun
30-
znesek: int
31-
cas: datetime = None
32-
opis: str = None
28+
class Transakcija(Entiteta):
29+
id: int = stolpec(glavni_kljuc=True, stevec=True)
30+
racun: Racun = stolpec(obvezen=True)
31+
znesek: int = stolpec(obvezen=True)
32+
cas: datetime = stolpec(privzeto=Funkcija("NOW()"), obvezen=True)
33+
opis: str = stolpec()
34+
35+
36+
def ustvari_tabele(izbrisi=False, ce_ne_obstajajo=False):
37+
with conn.transaction():
38+
if izbrisi:
39+
izbrisi_tabele(ce_ne_obstajajo)
40+
for entiteta in ENTITETE:
41+
entiteta.ustvari_tabelo(ce_ne_obstaja=ce_ne_obstajajo)
42+
43+
44+
def izbrisi_tabele(ce_obstajajo=False):
45+
with conn.transaction():
46+
for entiteta in reversed(ENTITETE):
47+
entiteta.izbrisi_tabelo(ce_obstajajo)
48+
49+
50+
ENTITETE = (Kraj, Oseba, Racun, Transakcija)
51+
conn = povezi(**auth)
52+
ustvari_tabele(ce_ne_obstajajo=True)

predavanja/primeri/banka/orm.py

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
from dataclasses import field, fields
2+
from datetime import datetime
3+
from psycopg import connect, sql, errors
4+
import csv
5+
6+
7+
TIPI = {
8+
int: "INTEGER",
9+
str: "TEXT",
10+
datetime: "TIMESTAMP(0)"
11+
}
12+
13+
14+
LASTNOSTI = {
15+
"glavni_kljuc": "PRIMARY KEY",
16+
"obvezen": "NOT NULL",
17+
"enolicen": "UNIQUE"
18+
}
19+
20+
21+
def povezi(*largs, **kwargs):
22+
"""
23+
Vzpostavi povezavo z bazo.
24+
"""
25+
global conn
26+
conn = connect(*largs, **kwargs, autocommit=True)
27+
return conn
28+
29+
30+
def stolpec(privzeto=None, glavni_kljuc=False, stevec=False, obvezen=False,
31+
enolicen=False):
32+
return field(default=privzeto,
33+
metadata=dict(glavni_kljuc=glavni_kljuc, stevec=stevec,
34+
obvezen=obvezen, enolicen=enolicen))
35+
36+
37+
def tip(stolpec):
38+
t = stolpec.type
39+
while issubclass(t, Entiteta):
40+
t = t.glavni_kljuc().type
41+
return TIPI[t]
42+
43+
44+
class Funkcija:
45+
def __init__(self, niz):
46+
self.niz = sql.SQL(niz)
47+
48+
49+
class Entiteta:
50+
@classmethod
51+
def ustvari_tabelo(cls, pobrisi=False, ce_ne_obstaja=False):
52+
with conn.transaction():
53+
if pobrisi:
54+
cls.izbrisi_tabelo(ce_ne_obstaja)
55+
with conn.cursor() as cur:
56+
niz = sql.SQL("""
57+
CREATE TABLE {ce_ne_obstaja} {tabela} ({stolpci});
58+
""").format(
59+
ce_ne_obstaja=sql.SQL("IF NOT EXISTS" if ce_ne_obstaja else ""),
60+
tabela=sql.Identifier(cls.tabela()),
61+
stolpci=sql.SQL(", ").join(
62+
sql.SQL("{ime} {tip} {lastnosti} {privzeto} {referenca}").format(
63+
ime=sql.Identifier(stolpec.name),
64+
tip=sql.SQL("SERIAL" if stolpec.metadata["stevec"] else tip(stolpec)),
65+
lastnosti=sql.SQL(" ").join(
66+
sql.SQL(niz) for lastnost, niz in LASTNOSTI.items()
67+
if stolpec.metadata[lastnost]
68+
),
69+
privzeto=sql.SQL("DEFAULT {vrednost}").format(
70+
vrednost=stolpec.default.niz if isinstance(stolpec.default, Funkcija)
71+
else sql.Literal(stolpec.default)
72+
) if stolpec.default else sql.SQL(""),
73+
referenca=sql.SQL("REFERENCES {tab}({st})").format(
74+
tab=sql.Identifier(stolpec.type.tabela()),
75+
st=sql.Identifier(stolpec.type.glavni_kljuc().name)
76+
) if issubclass(stolpec.type, Entiteta) else sql.SQL("")
77+
)
78+
for stolpec in fields(cls)
79+
))
80+
cur.execute(niz)
81+
82+
@classmethod
83+
def izbrisi_tabelo(cls, ce_obstaja=False):
84+
with conn.transaction():
85+
with conn.cursor() as cur:
86+
cur.execute(sql.SQL("DROP TABLE {ce_obstaja} {tabela};").format(
87+
ce_obstaja=sql.SQL("IF EXISTS" if ce_obstaja else ""),
88+
tabela=sql.Identifier(cls.tabela())
89+
))
90+
91+
@classmethod
92+
def tabela(cls):
93+
if not hasattr(cls, "TABELA"):
94+
cls.TABELA = cls.__name__.lower()
95+
return cls.TABELA
96+
97+
@classmethod
98+
def glavni_kljuc(cls):
99+
if not hasattr(cls, "GLAVNI_KLJUC"):
100+
cls.GLAVNI_KLJUC = next(stolpec for stolpec in fields(cls) if stolpec.metadata["glavni_kljuc"])
101+
return cls.GLAVNI_KLJUC
102+
103+
@classmethod
104+
def uvozi_podatke(cls):
105+
with open(f"podatki/{cls.tabela()}.csv"):
106+
rd = csv.reader(f)
107+
stolpci = next(rd)
108+
for vrstica in rd:
109+
# vstavi podatke v bazo
110+
pass

0 commit comments

Comments
 (0)