Skip to content

Commit ebfd298

Browse files
committed
Dodelane osnovne funkcionalnosti ORM
1 parent 1741a8c commit ebfd298

File tree

1 file changed

+200
-18
lines changed
  • predavanja/primeri/banka

1 file changed

+200
-18
lines changed

predavanja/primeri/banka/orm.py

Lines changed: 200 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44
import csv
55

66

7+
PRAZNO = sql.SQL("")
8+
PRESLEDEK = sql.SQL(" ")
9+
VEJICA = sql.SQL(", ")
10+
711
TIPI = {
812
int: "INTEGER",
913
str: "TEXT",
@@ -29,82 +33,260 @@ def povezi(*largs, **kwargs):
2933

3034
def stolpec(privzeto=None, glavni_kljuc=False, stevec=False, obvezen=False,
3135
enolicen=False):
36+
"""
37+
Vrni polje, ki opisuje stolpec v tabeli.
38+
"""
3239
return field(default=privzeto,
3340
metadata=dict(glavni_kljuc=glavni_kljuc, stevec=stevec,
3441
obvezen=obvezen, enolicen=enolicen))
3542

3643

3744
def tip(stolpec):
45+
"""
46+
Vrni tip stolpca v tabeli.
47+
"""
3848
t = stolpec.type
3949
while issubclass(t, Entiteta):
4050
t = t.glavni_kljuc().type
4151
return TIPI[t]
4252

4353

4454
class Funkcija:
55+
"""
56+
Razred za definicije funkcij v SQL.
57+
"""
4558
def __init__(self, niz):
4659
self.niz = sql.SQL(niz)
4760

4861

4962
class Entiteta:
63+
"""
64+
Nadrazred za posamezne entitetne tipe.
65+
"""
66+
67+
def __post_init__(self):
68+
"""
69+
Inicializiraj polje z ID-jem iz baze.
70+
"""
71+
self.__dbid = None
72+
73+
def __getitem__(self, kljuc):
74+
"""
75+
Vrni vrednost v stolpcu v obliki, kot je zapisana v bazi.
76+
"""
77+
vrednost = getattr(self, kljuc)
78+
if isinstance(vrednost, Entiteta):
79+
return vrednost[vrednost.glavni_kljuc().name]
80+
else:
81+
return vrednost
82+
83+
def __nastavi_id(self):
84+
"""
85+
Nastavi ID na glavni ključ.
86+
"""
87+
self.__dbid = self[self.glavni_kljuc().name]
88+
5089
@classmethod
5190
def ustvari_tabelo(cls, pobrisi=False, ce_ne_obstaja=False):
91+
"""
92+
Ustvari tabelo v bazi.
93+
"""
5294
with conn.transaction():
5395
if pobrisi:
5496
cls.izbrisi_tabelo(ce_ne_obstaja)
5597
with conn.cursor() as cur:
56-
niz = sql.SQL("""
98+
cur.execute(sql.SQL("""
5799
CREATE TABLE {ce_ne_obstaja} {tabela} ({stolpci});
58100
""").format(
59-
ce_ne_obstaja=sql.SQL("IF NOT EXISTS" if ce_ne_obstaja else ""),
101+
ce_ne_obstaja=sql.SQL("IF NOT EXISTS"
102+
if ce_ne_obstaja else ""),
60103
tabela=sql.Identifier(cls.tabela()),
61-
stolpci=sql.SQL(", ").join(
62-
sql.SQL("{ime} {tip} {lastnosti} {privzeto} {referenca}").format(
104+
stolpci=VEJICA.join(
105+
sql.SQL("""
106+
{ime} {tip} {lastnosti} {privzeto} {referenca}
107+
""").format(
63108
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()
109+
tip=sql.SQL("SERIAL" if stolpec.metadata["stevec"]
110+
else tip(stolpec)),
111+
lastnosti=PRESLEDEK.join(
112+
sql.SQL(niz)
113+
for lastnost, niz in LASTNOSTI.items()
67114
if stolpec.metadata[lastnost]
68115
),
69116
privzeto=sql.SQL("DEFAULT {vrednost}").format(
70-
vrednost=stolpec.default.niz if isinstance(stolpec.default, Funkcija)
117+
vrednost=stolpec.default.niz
118+
if isinstance(stolpec.default, Funkcija)
71119
else sql.Literal(stolpec.default)
72-
) if stolpec.default else sql.SQL(""),
120+
) if stolpec.default else PRAZNO,
73121
referenca=sql.SQL("REFERENCES {tab}({st})").format(
74122
tab=sql.Identifier(stolpec.type.tabela()),
75123
st=sql.Identifier(stolpec.type.glavni_kljuc().name)
76-
) if issubclass(stolpec.type, Entiteta) else sql.SQL("")
124+
) if issubclass(stolpec.type, Entiteta)
125+
else PRAZNO
77126
)
78127
for stolpec in fields(cls)
79-
))
80-
cur.execute(niz)
128+
)))
81129

82130
@classmethod
83131
def izbrisi_tabelo(cls, ce_obstaja=False):
132+
"""
133+
Izbriši tabelo iz baze.
134+
"""
84135
with conn.transaction():
85136
with conn.cursor() as cur:
86-
cur.execute(sql.SQL("DROP TABLE {ce_obstaja} {tabela};").format(
137+
cur.execute(sql.SQL("""
138+
DROP TABLE {ce_obstaja} {tabela};
139+
""").format(
87140
ce_obstaja=sql.SQL("IF EXISTS" if ce_obstaja else ""),
88141
tabela=sql.Identifier(cls.tabela())
89142
))
90143

91144
@classmethod
92145
def tabela(cls):
146+
"""
147+
Vrni ime tabele.
148+
"""
93149
if not hasattr(cls, "TABELA"):
94150
cls.TABELA = cls.__name__.lower()
95151
return cls.TABELA
96152

97153
@classmethod
98154
def glavni_kljuc(cls):
155+
"""
156+
Vrni definicijo glavnega ključa.
157+
"""
99158
if not hasattr(cls, "GLAVNI_KLJUC"):
100-
cls.GLAVNI_KLJUC = next(stolpec for stolpec in fields(cls) if stolpec.metadata["glavni_kljuc"])
159+
cls.GLAVNI_KLJUC = next(stolpec for stolpec in fields(cls)
160+
if stolpec.metadata["glavni_kljuc"])
101161
return cls.GLAVNI_KLJUC
102162

103163
@classmethod
104164
def uvozi_podatke(cls):
105-
with open(f"podatki/{cls.tabela()}.csv"):
165+
"""
166+
Uvozi podatke v tabelo.
167+
"""
168+
with open(f"podatki/{cls.tabela()}.csv") as f:
106169
rd = csv.reader(f)
107170
stolpci = next(rd)
108-
for vrstica in rd:
109-
# vstavi podatke v bazo
110-
pass
171+
with conn.transaction():
172+
with conn.cursor() as cur:
173+
cur.executemany(sql.SQL("""
174+
INSERT INTO {tabela} ({stolpci}) VALUES ({podatki});
175+
""").format(
176+
tabela=sql.Identifier(cls.tabela()),
177+
stolpci=VEJICA.join(
178+
sql.Identifier(stolpec) for stolpec in stolpci
179+
),
180+
podatki=VEJICA.join(
181+
sql.Placeholder(stolpec) for stolpec in stolpci
182+
)
183+
), ({stolpec: (podatek if podatek else None)
184+
for stolpec, podatek in zip(stolpci, vrstica)}
185+
for vrstica in rd))
186+
187+
@classmethod
188+
def z_id(cls, id):
189+
"""
190+
Vrni entiteto s podanim ID-jem.
191+
"""
192+
with conn.cursor() as cur:
193+
cur.execute(sql.SQL("""
194+
SELECT {stolpci} FROM {tabela}
195+
WHERE {glavni_kljuc} = {id};
196+
""").format(
197+
stolpci=VEJICA.join(sql.Identifier(stolpec.name)
198+
for stolpec in fields(cls)),
199+
tabela=sql.Identifier(cls.tabela()),
200+
glavni_kljuc=sql.Identifier(cls.glavni_kljuc().name),
201+
id=sql.Literal(id)
202+
))
203+
vrstica = cur.fetchone()
204+
if not vrstica:
205+
raise ValueError(f'{cls.__name__} z ID-jem {id} ne obstaja!')
206+
self = cls(*vrstica)
207+
self.__nastavi_id()
208+
return self
209+
210+
def vstavi(self):
211+
"""
212+
Vstavi entiteto v tabelo.
213+
"""
214+
stolpci = []
215+
podatki = []
216+
generirani = []
217+
for stolpec in fields(self):
218+
vrednost = self[stolpec.name]
219+
if vrednost is not None:
220+
stolpci.append(stolpec.name)
221+
if isinstance(vrednost, Funkcija):
222+
podatki.append(vrednost.niz)
223+
generirani.append(stolpec.name)
224+
else:
225+
podatki.append(sql.Literal(vrednost))
226+
elif stolpec.metadata["stevec"]:
227+
generirani.append(stolpec.name)
228+
with conn.transaction():
229+
with conn.cursor() as cur:
230+
cur.execute(sql.SQL("""
231+
INSERT INTO {tabela} ({stolpci}) VALUES ({podatki})
232+
{generirano};
233+
""").format(
234+
tabela=sql.Identifier(self.tabela()),
235+
stolpci=VEJICA.join(sql.Identifier(stolpec)
236+
for stolpec in stolpci),
237+
podatki=VEJICA.join(podatki),
238+
generirano=sql.SQL("RETURNING {generirani}").format(
239+
generirani=VEJICA.join(sql.Identifier(stolpec)
240+
for stolpec in generirani)
241+
) if generirani else PRAZNO
242+
))
243+
if generirani:
244+
for kljuc, vrednost in zip(generirani, cur.fetchone()):
245+
setattr(self, kljuc, vrednost)
246+
self.__nastavi_id()
247+
248+
def posodobi(self):
249+
"""
250+
Posodobi entiteto v bazi.
251+
"""
252+
assert self.__dbid is not None, "Entiteta še ni v bazi!"
253+
with conn.transaction():
254+
with conn.cursor() as cur:
255+
cur.execute(sql.SQL("""
256+
UPDATE {tabela} SET {vrednosti}
257+
WHERE {glavni_kljuc} = {id};
258+
""").format(
259+
tabela=sql.Identifier(self.tabela()),
260+
vrednosti=VEJICA.join(
261+
sql.SQL("""
262+
{stolpec} = {vrednost}
263+
""").format(
264+
stolpec=sql.Identifier(stolpec.name),
265+
vrednost=vrednost.niz
266+
if isinstance(vrednost, Funkcija)
267+
else sql.Literal(vrednost)
268+
)
269+
for stolpec in fields(self)
270+
for vrednost in [self[stolpec.name]]
271+
),
272+
glavni_kljuc=sql.Identifier(self.glavni_kljuc().name),
273+
id=sql.Literal(self.__dbid)
274+
))
275+
self.__nastavi_id()
276+
277+
def izbrisi(self):
278+
"""
279+
Izbriši entiteto iz baze.
280+
"""
281+
assert self.__dbid is not None, "Entiteta še ni v bazi!"
282+
with conn.transaction():
283+
with conn.cursor() as cur:
284+
cur.execute(sql.SQL("""
285+
DELETE FROM {tabela}
286+
WHERE {glavni_kljuc} = {id};
287+
""").format(
288+
tabela=sql.Identifier(self.tabela()),
289+
glavni_kljuc=sql.Identifier(self.glavni_kljuc().name),
290+
id=sql.Literal(self.__dbid)
291+
))
292+
self.__dbid = None

0 commit comments

Comments
 (0)