ebSkola

10.6 Noslēguma projekts: Highscore datubāze

Stundas uzdevums: Apvienot visas tēmas prasmes - projektēt, izveidot un Python kodā lietot pilnvērtīgu datubāzi spēļu rezultātu glabāšanai un statistikai.

SR 2.4.17. Darbs ar failiem un ārējām datu krātuvēm SR 2.4.4. Iegūst, atlasa un apstrādā datus SR 2.4.5. Datu analīze un vizualizācija SR 2.4.15. Modulāras programmas un funkcijas

70 min plāns: Ievads un kritēriju pārruna (~10 min) · 1. uzdevums (~15 min) - izveido trīs tabulu shēmu · 2. uzdevums (~25 min) - uzraksti Python funkcijas rezultātu pievienošanai · 3. uzdevums (~20 min) - izveido TOP sarakstu un statistiku. Papildu uzdevumu sāc tikai tad, ja pārējie trīs ir gatavi.

Pirms sāc: šis ir 10. tēmas noslēguma projekts. Vajadzēs PostgreSQL un psycopg2. Sāc ar shēmu README.md failā vai diagrammu rīkā, pirms raksti SQL.

Teorija: Spēles apraksts un arhitektūra

Tavs uzdevums ir izveidot pilnvērtīgu Highscore datubāzi - Python lietotnes, kas:

  • Pieņem spēles rezultātus no jebkuras spēles (caur funkciju izsaukumu).
  • Glabā tos PostgreSQL datubāzē ar pareizām attiecībām.
  • Atgriež filtrētus TOP saraksti (pēc spēles, pēc datumu intervāla).
  • Aprēķina statistiku (vidējais, rekords, spēļu skaits).

Datu modelis (3 tabulas):

speletaji (id, vards, izveidots)
speles_veidi (id, nosaukums)
rezultati (id, speletajs_id, speles_veids_id, punkti, spelets)

Praktiskie uzdevumi

1. uzdevums -

Izveido trīs tabulu shēmu

Beigās tavā datubāzē būs pareizi saistītas trīs tabulas.

  1. Izveido failu schema.sql.
  2. Uzraksti tabulu speletaji ar id un unikālu vards.
  3. Uzraksti tabulu speles_veidi ar id un unikālu nosaukums.
  4. Uzraksti tabulu rezultati ar ārējām atslēgām uz abām iepriekšējām.
  5. Pievieno rezultati tabulai punkti ar CHECK un datums.
  6. Izpildi skriptu un pārbaudi visas trīs tabulas.

Gatavs, kad: visas trīs tabulas eksistē, un rezultati nevar ievadīt bez esoša spēlētāja un spēles veida.

2. uzdevums -

Uzraksti Python funkcijas rezultātu pievienošanai

Beigās jebkura tava spēle varēs saglabāt rezultātu ar vienu izsaukumu.

  1. Izveido failu highscore.py.
  2. Uzraksti funkciju def pievieno_rezultatu(vards, speles_veids, punkti):.
  3. Atrodi vai izveido spēlētāju un atgriez viņa id.
  4. Atrodi vai izveido spēles veidu un atgriez tā id.
  5. Ievadi rezultātu, izmantojot %s vietturus.
  6. Izsauc funkciju piecas reizes ar dažādiem datiem.
  7. Pārbaudi datubāzē, ka spēlētāji nedublējas.

Gatavs, kad: pēc pieciem izsaukumiem tabulā rezultati ir 5 rindas, bet katrs spēlētājs ir tikai vienreiz.

3. uzdevums -

Izveido TOP sarakstu un statistiku

Beigās tava programma atgriezīs gatavu rezultātu tabulu.

  1. Uzraksti funkciju def top_saraksts(speles_veids, limits=5):.
  2. Izmanto tajā JOIN starp visām trim tabulām.
  3. Pievieno WHERE pēc spēles veida un ORDER BY pēc punktiem.
  4. Uzraksti otru funkciju, kas atgriež vidējo, rekordu un spēļu skaitu.
  5. Izdrukā abu funkciju rezultātus glītā tabulā.
  6. Veic commit ar ziņu Pievieno highscore datubazi un push.
  7. Iesniedz krātuves saiti skolotājam.

Gatavs, kad: TOP saraksts atgriež tieši norādītās spēles rezultātus, sakārtotus no labākā.

Papildu uzdevums - Filtrē pēc datumu intervāla

Ja pamatdarbs ir gatavs, ļauj skatīt tikai šīs nedēļas rezultātus.

  1. Pievieno funkcijai parametrus no_datuma un lidz_datumam.
  2. Papildini vaicājumu ar WHERE datums BETWEEN %s AND %s.
  3. Izsauc funkciju ar pēdējo septiņu dienu intervālu.
  4. Pārbaudi, ka vecāki rezultāti neparādās.
  5. Pārbaudi, ka tukšs intervāls neizraisa kļūdu.

Gatavs, kad: vaicājums atgriež tikai norādītā intervāla rezultātus, un tukšs intervāls dod tukšu sarakstu.

Biežākās kļūdas

  • ON CONFLICT vajadzīgs UNIQUE: Lai INSERT ... ON CONFLICT (vards) DO NOTHING strādātu, laukam jābūt UNIQUE.
  • Datu izmaiņas neredz: Aizmirsi conn.commit().
  • JOIN neatgriež datus: Pārbaudi, vai FK norāda uz pareizu PK un dati ir saglabāti pareizās tabulās.

Koda piemērs

-- Pilna shēma + 1 testa rezultāts
CREATE TABLE speletaji (
    id SERIAL PRIMARY KEY,
    vards TEXT NOT NULL UNIQUE
);

CREATE TABLE speles_veidi (
    id SERIAL PRIMARY KEY,
    nosaukums TEXT NOT NULL UNIQUE
);

CREATE TABLE rezultati (
    id SERIAL PRIMARY KEY,
    speletajs_id INTEGER REFERENCES speletaji(id) ON DELETE CASCADE,
    speles_veids_id INTEGER REFERENCES speles_veidi(id),
    punkti INTEGER NOT NULL CHECK (punkti >= 0),
    spelets TIMESTAMP DEFAULT NOW()
);

INSERT INTO speletaji (vards) VALUES ('Anna');
INSERT INTO speles_veidi (nosaukums) VALUES ('Skaitļu minētājs');
INSERT INTO rezultati (speletajs_id, speles_veids_id, punkti) VALUES (1, 1, 95);

SELECT s.vards, sv.nosaukums, r.punkti
FROM rezultati r
JOIN speletaji s ON s.id = r.speletajs_id
JOIN speles_veidi sv ON sv.id = r.speles_veids_id;
vards | nosaukums | punkti
------|-------------------|-------
Anna | Skaitļu minētājs | 95