diff --git a/FlaskWebProject/FlaskWebProject/lewy_api_v1.py b/FlaskWebProject/FlaskWebProject/lewy_api_v1.py index c1fc7ef..53ec3f2 100644 --- a/FlaskWebProject/FlaskWebProject/lewy_api_v1.py +++ b/FlaskWebProject/FlaskWebProject/lewy_api_v1.py @@ -2,6 +2,7 @@ # - HTTP status code, # - human-readable status message, # - json with appropriate data +from datetime import datetime from flask_sqlalchemy import SQLAlchemy from functools import wraps from lewy_globals import getDb, colors as c diff --git a/FlaskWebProject/FlaskWebProject/lewy_db.py b/FlaskWebProject/FlaskWebProject/lewy_db.py index e87203e..bd14db5 100644 --- a/FlaskWebProject/FlaskWebProject/lewy_db.py +++ b/FlaskWebProject/FlaskWebProject/lewy_db.py @@ -1,6 +1,6 @@ from datetime import datetime from flask_sqlalchemy import SQLAlchemy -from sqlalchemy import ForeignKey, select +from sqlalchemy import ForeignKey, select, insert, update from sqlalchemy.orm import Mapped, mapped_column, DeclarativeBase, Session, relationship from typing import List import toml @@ -27,17 +27,20 @@ class baza(): class sportowcy(Base): __tablename__ = tnp + "sportowcy" - id_zawodnika: Mapped[ int] = mapped_column(primary_key=True) - zewnetrzne_id_zawodnika: Mapped[ str] = mapped_column() + id_zawodnika: Mapped[ int] = mapped_column(primary_key=True, autoincrement=True) + zewnetrzne_id_zawodnika: Mapped[ str] = mapped_column(unique=True) + imie: Mapped[ str] = mapped_column() + nazwisko: Mapped[ str] = mapped_column() data_urodzenia: Mapped[ str] = mapped_column() czy_aktywny: Mapped[ bool] = mapped_column() klub_id: Mapped[ List[str]] = mapped_column(ForeignKey(f"{tnp}kluby.id_klubu")) klub: Mapped[ List["kluby"]] = relationship(back_populates="sportowcy_w_klubie", foreign_keys=[klub_id]) narodowosc: Mapped[ str] = mapped_column() ilosc_trofeow: Mapped[ int] = mapped_column() - ostatnie_trofeum_id: Mapped[ int] = mapped_column(ForeignKey(f"{tnp}trofea.id_trofeum")) + ostatnie_trofeum_id: Mapped[ int] = mapped_column(ForeignKey(f"{tnp}trofea.id_trofeum"), nullable=True) ostatnie_trofeum: Mapped[ "trofea"] = relationship(back_populates="zawodnik", foreign_keys=[ostatnie_trofeum_id]) - pierwszy_mecz: Mapped[ int] = mapped_column() + pierwszy_mecz_id: Mapped[ int] = mapped_column(ForeignKey(f"{tnp}mecze.id_meczu")) + pierwszy_mecz: Mapped[ "mecze"] = relationship() wycena: Mapped[ int] = mapped_column() ostatni_gol_dla_id: Mapped[ str] = mapped_column(ForeignKey(f"{tnp}kluby.id_klubu")) ostatni_gol_dla: Mapped[ "kluby"] = relationship(back_populates="sportowcy_ostatni_gol", foreign_keys=[ostatni_gol_dla_id]) @@ -45,18 +48,20 @@ class baza(): statystyki: Mapped[List["statystyki_sportowcow"]] = relationship(back_populates="sportowiec") trofea: Mapped[ List["trofea"]] = relationship(back_populates="zawodnik", foreign_keys="[trofea.id_zawodnika]") + # Co było pierwsze, jajko czy kura? https://docs.sqlalchemy.org/en/20/orm/relationship_persistence.html#rows-that-point-to-themselves-mutually-dependent-rows + # Kiepskie rozwiązanie, ale jednak działające: pozwolić obcym kluczom na bycie "null" class trofea(Base): __tablename__ = tnp + "trofea" - id_trofeum: Mapped[ int] = mapped_column(primary_key=True) - id_zawodnika: Mapped[ int] = mapped_column(ForeignKey(f"{tnp}sportowcy.id_zawodnika")) - zawodnik: Mapped[ "sportowcy"] = relationship(back_populates="trofea", foreign_keys=[id_zawodnika]) + id_trofeum: Mapped[ int] = mapped_column(primary_key=True, autoincrement=True) + id_zawodnika: Mapped[ int] = mapped_column(ForeignKey(f"{tnp}sportowcy.id_zawodnika", name="fk_zawodnik"), nullable=True) + zawodnik: Mapped[ "sportowcy"] = relationship(back_populates="trofea", foreign_keys=[id_zawodnika], post_update=True) nazwa: Mapped[ str] = mapped_column() sezon: Mapped[ str] = mapped_column() - rok: Mapped[ str] = mapped_column() + rok: Mapped[ int] = mapped_column() class sportowcy_w_meczach(Base): __tablename__ = tnp + "sportowcy_w_meczach" - id_rekordu: Mapped[ int] = mapped_column(primary_key=True) + id_rekordu: Mapped[ int] = mapped_column(primary_key=True, autoincrement=True) id_zawodnika: Mapped[ int] = mapped_column(ForeignKey(f"{tnp}sportowcy.id_zawodnika")) zawodnik: Mapped[ "sportowcy"] = relationship() zewnetrzne_id_meczu: Mapped[ str] = mapped_column(ForeignKey(f"{tnp}mecze.zewnetrzne_id_meczu")) @@ -72,7 +77,7 @@ class baza(): class statystyki_sportowcow(Base): __tablename__ = tnp + "statystyki_sportowcow" - id_statystyki: Mapped[ int] = mapped_column(primary_key=True) + id_statystyki: Mapped[ int] = mapped_column(primary_key=True, autoincrement=True) sportowiec: Mapped[ "sportowcy"] = relationship(back_populates="statystyki") ostatni_mecz: Mapped[ int] = mapped_column(ForeignKey(f"{tnp}mecze.id_meczu")) ilosc_wystapien: Mapped[ int] = mapped_column() @@ -98,7 +103,7 @@ class baza(): class mecze(Base): __tablename__ = tnp + "mecze" - id_meczu: Mapped[ int] = mapped_column(primary_key=True) + id_meczu: Mapped[ int] = mapped_column(primary_key=True, autoincrement=True) zewnetrzne_id_meczu: Mapped[ str] = mapped_column(unique=True) data: Mapped[ datetime] = mapped_column() gospodarze_id: Mapped[ str] = mapped_column(ForeignKey(f"{tnp}kluby.id_klubu")) @@ -131,4 +136,108 @@ class baza(): filter_by(**kwargs) ).scalars() + def simple_insert_one(self, type, **kwargs): + """ + Użycie: + simple_insert_one(ldb.kluby, id_klubu="polska", pelna_nazwa="Reprezentacja Polski", skrocona_nazwa="PL") + https://docs.sqlalchemy.org/en/20/tutorial/data_insert.html + https://docs.sqlalchemy.org/en/20/orm/session_basics.html + """ + obj = type(**kwargs) + with Session(self.db.engine) as session: + session.add(obj) + session.commit() + return 0 + return 1 + + def simple_insert_many(self, objs_list): + """ + Użycie: + simple_insert_many([sportowiec_a, sportowiec_b]) + + https://docs.sqlalchemy.org/en/20/tutorial/data_insert.html + https://docs.sqlalchemy.org/en/20/orm/session_basics.html + """ + with Session(self.db.engine) as session: + session.add_all(objs_list) + session.commit() + return 0 + return 1 + + def sample_data_init(self, override_safety_check=False): + """ + Użycie: + sample_data_init() + Uwaga! Poniższe populuje pustą bazę danych. + Nie należy tego używać na nie-pustej bazie, ponieważ spowoduje + to wpisanie śmieciowych danych! + Jeżeli wiesz co robisz w takiej sytuacji, uruchom metodę z: + sample_data_init(override_safety_check=True) + Metoda głównie używana do testów. + """ + is_table_empty = self.simple_select_all(sportowcy, zewnetrzne_id_zawodnika="MVC8zHZD").one() is None + if not is_table_empty and not override_safety_check: + raise EnvironmentError("sample_data_init() ran on a non-empty database. Ignore with override_safety_check=True.") + + with Session(self.db.engine) as session: + self.simple_insert_one(kluby, + id_klubu="undefined", + pelna_nazwa="Klub niezdefiniowany", + skrocona_nazwa="N/A") + self.simple_insert_one(mecze, + zewnetrzne_id_meczu="dummy_match", + data=datetime.strptime("1970-01-01 00:00:00", '%Y-%m-%d %H:%M:%S'), + gospodarze_id="undefined", + goscie_id="undefined", + gosp_wynik=0, + gosc_wynik=0, + sezon="1970/1970", + nazwa_turnieju="Nieznany turniej", + skrocona_nazwa_turnieju="N/A", + flaga=0) + self.simple_insert_one(statystyki_sportowcow, + ostatni_mecz=1, + ilosc_wystapien=0, + minut_gry=0, + gier_sum=0, + goli_sum=0, + asyst_sum=0, + interwencji_sum=0, + nieobronionych_interwencji_sum=0, + zoltych_kartek_sum=0, + czerwonych_kartek_sum=0, + wygranych_sum=0, + wynik_sum=0, + meczow_do_wynikow_sum=0) + + sportowiec = sportowcy( + zewnetrzne_id_zawodnika="MVC8zHZD", + imie="Robert", + nazwisko="Lewandowski", + data_urodzenia="21.08.1988", + czy_aktywny=True, + klub_id="undefined", + narodowosc="PL", + ilosc_trofeow=0, + pierwszy_mecz_id=1, + ostatni_gol_dla_id="undefined", + statystyki_id=1, + wycena=64_940_000) + trofeum = trofea( + nazwa="Nieznane trofeum", + sezon="0000/0000", + rok=1970) + + session.add(sportowiec) + session.flush() + + session.add(trofeum) + session.flush() + + trofeum.zawodnik = sportowiec + sportowiec.ostatnie_trofeum = trofeum + + session.commit() + return 0 + return 1 \ No newline at end of file diff --git a/FlaskWebProject/FlaskWebProject/lewy_globals.py b/FlaskWebProject/FlaskWebProject/lewy_globals.py index 2a1dbfd..2d9f7af 100644 --- a/FlaskWebProject/FlaskWebProject/lewy_globals.py +++ b/FlaskWebProject/FlaskWebProject/lewy_globals.py @@ -69,7 +69,7 @@ def getConfig(configfile): global randomly_generated_passcode if not os.path.exists(configfile): - dummy_config = {'general': {'db_path_url': 'sqlite:///lewangoalski.sqlite', 'is_proxied': False, 'public_facing_url': 'http://127.0.0.1:5000/', 'db_prefix': 'lewy_sqlite'}, 'api': {'api_key': 'CHANGEME'}, 'scraper': {'user-agent': ''}} + dummy_config = {'general': {'db_path_url': 'sqlite:///lewangoalski.sqlite', 'is_proxied': False, 'public_facing_url': 'http://127.0.0.1:5000/', 'db_prefix': 'lewy_sqlite'}, 'api': {'api_key': 'CHANGEME'}, 'scraper': {'user-agent': ''}, 'sportsmen': {'tracked_ids': ["MVC8zHZD", "WGOY4FSt", "vgOOdZbd", "Wn6E2SED", "AiH2zDve", "dUShzrBp", "UmV9iQmE", "tpV0VX0S", "vw8ZV7HC", "Qgx2trzH", "2oMimkAU", "WfXv1DCa", "0vgcq6un", "v5HSlEAa", "4S9fNUYh"]}} # if a passcode has not been provided by the user (config file doesn't exist, and user didn't specify it using an argument) print(f"{colors.WARNING}WARNING{colors.ENDC}: Using default, baked in config data. {colors.ENDL}" f" Consider copying and editing the provided example file ({colors.OKCYAN}config.example.toml{colors.ENDC}).")