Improve typing
All checks were successful
Build Formula10 Docker Image / build-docker (push) Successful in 23s
All checks were successful
Build Formula10 Docker Image / build-docker (push) Successful in 23s
This commit is contained in:
@ -1,10 +1,11 @@
|
|||||||
import csv
|
import csv
|
||||||
import os.path
|
import os.path
|
||||||
|
from typing import List, Any
|
||||||
from model import *
|
from flask_sqlalchemy import SQLAlchemy
|
||||||
|
from model import Team, Driver, Race, User, RaceResult, RaceGuess, TeamWinners, PodiumDrivers, SeasonGuess
|
||||||
|
|
||||||
|
|
||||||
def load_csv(filename):
|
def load_csv(filename: str) -> List[List[str]]:
|
||||||
if not os.path.exists(filename):
|
if not os.path.exists(filename):
|
||||||
print(f"Could not load data from file {filename}, as it doesn't exist!")
|
print(f"Could not load data from file {filename}, as it doesn't exist!")
|
||||||
return []
|
return []
|
||||||
@ -15,7 +16,7 @@ def load_csv(filename):
|
|||||||
return list(reader)
|
return list(reader)
|
||||||
|
|
||||||
|
|
||||||
def write_csv(filename, objects):
|
def write_csv(filename: str, objects: List[Any]):
|
||||||
if len(objects) == 0:
|
if len(objects) == 0:
|
||||||
print(f"Could not write objects to file {filename}, as no objects were given!")
|
print(f"Could not write objects to file {filename}, as no objects were given!")
|
||||||
return
|
return
|
||||||
@ -28,15 +29,15 @@ def write_csv(filename, objects):
|
|||||||
|
|
||||||
|
|
||||||
# Reload static database data, this has to be called from the app context
|
# Reload static database data, this has to be called from the app context
|
||||||
def reload_static_data(db):
|
def reload_static_data(db: SQLAlchemy):
|
||||||
print("Initializing Database with Static Values...")
|
print("Initializing Database with Static Values...")
|
||||||
# Create it (if it doesn't exist!)
|
# Create it (if it doesn't exist!)
|
||||||
db.create_all()
|
db.create_all()
|
||||||
|
|
||||||
# Clear static data
|
# Clear static data
|
||||||
Team.query.delete()
|
db.session.query(Team).delete()
|
||||||
Driver.query.delete()
|
db.session.query(Driver).delete()
|
||||||
Race.query.delete()
|
db.session.query(Race).delete()
|
||||||
|
|
||||||
# Reload static data
|
# Reload static data
|
||||||
for row in load_csv("static_data/teams.csv"):
|
for row in load_csv("static_data/teams.csv"):
|
||||||
@ -49,18 +50,18 @@ def reload_static_data(db):
|
|||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
|
|
||||||
def reload_dynamic_data(db):
|
def reload_dynamic_data(db: SQLAlchemy):
|
||||||
print("Initializing Database with Dynamic Values...")
|
print("Initializing Database with Dynamic Values...")
|
||||||
# Create it (if it doesn't exist!)
|
# Create it (if it doesn't exist!)
|
||||||
db.create_all()
|
db.create_all()
|
||||||
|
|
||||||
# Clear dynamic data
|
# Clear dynamic data
|
||||||
User.query.delete()
|
db.session.query(User).delete()
|
||||||
RaceResult.query.delete()
|
db.session.query(RaceResult).delete()
|
||||||
RaceGuess.query.delete()
|
db.session.query(RaceGuess).delete()
|
||||||
TeamWinners.query.delete()
|
db.session.query(TeamWinners).delete()
|
||||||
PodiumDrivers.query.delete()
|
db.session.query(PodiumDrivers).delete()
|
||||||
SeasonGuess.query.delete()
|
db.session.query(SeasonGuess).delete()
|
||||||
|
|
||||||
# Reload dynamic data
|
# Reload dynamic data
|
||||||
for row in load_csv("dynamic_data/users.csv"):
|
for row in load_csv("dynamic_data/users.csv"):
|
||||||
@ -82,12 +83,12 @@ def reload_dynamic_data(db):
|
|||||||
def export_dynamic_data():
|
def export_dynamic_data():
|
||||||
print("Exporting Userdata...")
|
print("Exporting Userdata...")
|
||||||
|
|
||||||
users = User.query.all()
|
users: List[User] = User.query.all()
|
||||||
raceresults = RaceResult.query.all()
|
raceresults: List[RaceResult] = RaceResult.query.all()
|
||||||
raceguesses = RaceGuess.query.all()
|
raceguesses: List[RaceGuess] = RaceGuess.query.all()
|
||||||
teamwinners = TeamWinners.query.all()
|
teamwinners: List[TeamWinners] = TeamWinners.query.all()
|
||||||
podiumdrivers = PodiumDrivers.query.all()
|
podiumdrivers: List[PodiumDrivers] = PodiumDrivers.query.all()
|
||||||
seasonguesses = SeasonGuess.query.all()
|
seasonguesses: List[SeasonGuess] = SeasonGuess.query.all()
|
||||||
|
|
||||||
write_csv("dynamic_data/users.csv", users)
|
write_csv("dynamic_data/users.csv", users)
|
||||||
write_csv("dynamic_data/raceresults.csv", raceresults)
|
write_csv("dynamic_data/raceresults.csv", raceresults)
|
||||||
|
54
formula10.py
54
formula10.py
@ -1,6 +1,6 @@
|
|||||||
from urllib.parse import unquote
|
from urllib.parse import unquote
|
||||||
|
|
||||||
from flask import Flask, render_template, request, redirect
|
from flask import Flask, render_template, request, redirect
|
||||||
|
from werkzeug import Response
|
||||||
from model import *
|
from model import *
|
||||||
from database_utils import reload_static_data, reload_dynamic_data, export_dynamic_data
|
from database_utils import reload_static_data, reload_dynamic_data, export_dynamic_data
|
||||||
from template_model import TemplateModel
|
from template_model import TemplateModel
|
||||||
@ -30,42 +30,42 @@ db.init_app(app)
|
|||||||
|
|
||||||
|
|
||||||
@app.route("/")
|
@app.route("/")
|
||||||
def root():
|
def root() -> Response:
|
||||||
return race_active_user("Everyone")
|
return redirect("/race/Everyone")
|
||||||
|
|
||||||
|
|
||||||
@app.route("/save/all", strict_slashes=False)
|
@app.route("/save/all")
|
||||||
def save():
|
def save() -> Response:
|
||||||
export_dynamic_data()
|
export_dynamic_data()
|
||||||
return redirect("/")
|
return redirect("/")
|
||||||
|
|
||||||
|
|
||||||
@app.route("/load/all")
|
@app.route("/load/all")
|
||||||
def load():
|
def load() -> Response:
|
||||||
reload_static_data(db)
|
reload_static_data(db)
|
||||||
reload_dynamic_data(db)
|
reload_dynamic_data(db)
|
||||||
return redirect("/")
|
return redirect("/")
|
||||||
|
|
||||||
|
|
||||||
@app.route("/load/static")
|
@app.route("/load/static")
|
||||||
def load_static():
|
def load_static() -> Response:
|
||||||
reload_static_data(db)
|
reload_static_data(db)
|
||||||
return redirect("/")
|
return redirect("/")
|
||||||
|
|
||||||
|
|
||||||
@app.route("/load/dynamic")
|
@app.route("/load/dynamic")
|
||||||
def load_dynamic():
|
def load_dynamic() -> Response:
|
||||||
reload_dynamic_data(db)
|
reload_dynamic_data(db)
|
||||||
return redirect("/")
|
return redirect("/")
|
||||||
|
|
||||||
|
|
||||||
@app.route("/race")
|
@app.route("/race")
|
||||||
def race_root():
|
def race_root() -> Response:
|
||||||
return redirect("/race/Everyone")
|
return redirect("/race/Everyone")
|
||||||
|
|
||||||
|
|
||||||
@app.route("/race/<user_name>")
|
@app.route("/race/<user_name>")
|
||||||
def race_active_user(user_name: str):
|
def race_active_user(user_name: str) -> str:
|
||||||
user_name = unquote(user_name)
|
user_name = unquote(user_name)
|
||||||
model = TemplateModel()
|
model = TemplateModel()
|
||||||
return render_template("race.jinja",
|
return render_template("race.jinja",
|
||||||
@ -74,7 +74,7 @@ def race_active_user(user_name: str):
|
|||||||
|
|
||||||
|
|
||||||
@app.route("/race-guess/<race_name>/<user_name>", methods=["POST"])
|
@app.route("/race-guess/<race_name>/<user_name>", methods=["POST"])
|
||||||
def race_guess_post(race_name: str, user_name: str):
|
def race_guess_post(race_name: str, user_name: str) -> Response:
|
||||||
race_name = unquote(race_name)
|
race_name = unquote(race_name)
|
||||||
user_name = unquote(user_name)
|
user_name = unquote(user_name)
|
||||||
|
|
||||||
@ -88,7 +88,7 @@ def race_guess_post(race_name: str, user_name: str):
|
|||||||
print("Error: Can't guess race result if the race result is already known!")
|
print("Error: Can't guess race result if the race result is already known!")
|
||||||
return redirect(f"/race/{quote(user_name)}")
|
return redirect(f"/race/{quote(user_name)}")
|
||||||
|
|
||||||
raceguess: RaceGuess | None = RaceGuess.query.filter_by(user_name=user_name, race_name=race_name).first()
|
raceguess: RaceGuess | None = db.session.query(RaceGuess).filter_by(user_name=user_name, race_name=race_name).first()
|
||||||
|
|
||||||
if raceguess is None:
|
if raceguess is None:
|
||||||
raceguess = RaceGuess()
|
raceguess = RaceGuess()
|
||||||
@ -104,12 +104,12 @@ def race_guess_post(race_name: str, user_name: str):
|
|||||||
|
|
||||||
|
|
||||||
@app.route("/season")
|
@app.route("/season")
|
||||||
def season_root():
|
def season_root() -> Response:
|
||||||
return redirect("/season/Everyone")
|
return redirect("/season/Everyone")
|
||||||
|
|
||||||
|
|
||||||
@app.route("/season/<user_name>")
|
@app.route("/season/<user_name>")
|
||||||
def season_active_user(user_name: str):
|
def season_active_user(user_name: str) -> str:
|
||||||
user_name = unquote(user_name)
|
user_name = unquote(user_name)
|
||||||
model = TemplateModel()
|
model = TemplateModel()
|
||||||
return render_template("season.jinja",
|
return render_template("season.jinja",
|
||||||
@ -118,7 +118,7 @@ def season_active_user(user_name: str):
|
|||||||
|
|
||||||
|
|
||||||
@app.route("/season-guess/<user_name>", methods=["POST"])
|
@app.route("/season-guess/<user_name>", methods=["POST"])
|
||||||
def season_guess_post(user_name: str):
|
def season_guess_post(user_name: str) -> Response:
|
||||||
user_name = unquote(user_name)
|
user_name = unquote(user_name)
|
||||||
guesses: List[str | None] = [
|
guesses: List[str | None] = [
|
||||||
request.form.get("hottakeselect"),
|
request.form.get("hottakeselect"),
|
||||||
@ -129,7 +129,7 @@ def season_guess_post(user_name: str):
|
|||||||
request.form.get("lostselect")
|
request.form.get("lostselect")
|
||||||
]
|
]
|
||||||
teamwinnerguesses: List[str | None] = [
|
teamwinnerguesses: List[str | None] = [
|
||||||
request.form.get(f"teamwinner-{team.name}") for team in Team.query.all()
|
request.form.get(f"teamwinner-{team.name}") for team in db.session.query(Team).all()
|
||||||
]
|
]
|
||||||
podiumdriverguesses: List[str] = request.form.getlist("podiumdrivers")
|
podiumdriverguesses: List[str] = request.form.getlist("podiumdrivers")
|
||||||
|
|
||||||
@ -137,7 +137,7 @@ def season_guess_post(user_name: str):
|
|||||||
print("Error: /guessseason could not obtain request data!")
|
print("Error: /guessseason could not obtain request data!")
|
||||||
return redirect(f"/season/{quote(user_name)}")
|
return redirect(f"/season/{quote(user_name)}")
|
||||||
|
|
||||||
seasonguess: SeasonGuess | None = SeasonGuess.query.filter_by(user_name=user_name).first()
|
seasonguess: SeasonGuess | None = db.session.query(SeasonGuess).filter_by(user_name=user_name).first()
|
||||||
teamwinners: TeamWinners | None = seasonguess.team_winners if seasonguess is not None else None
|
teamwinners: TeamWinners | None = seasonguess.team_winners if seasonguess is not None else None
|
||||||
podiumdrivers: PodiumDrivers | None = seasonguess.podium_drivers if seasonguess is not None else None
|
podiumdrivers: PodiumDrivers | None = seasonguess.podium_drivers if seasonguess is not None else None
|
||||||
|
|
||||||
@ -176,12 +176,12 @@ def season_guess_post(user_name: str):
|
|||||||
|
|
||||||
|
|
||||||
@app.route("/result")
|
@app.route("/result")
|
||||||
def result_root():
|
def result_root() -> Response:
|
||||||
return redirect("/result/Current")
|
return redirect("/result/Current")
|
||||||
|
|
||||||
|
|
||||||
@app.route("/result/<race_name>")
|
@app.route("/result/<race_name>")
|
||||||
def result_active_race(race_name: str):
|
def result_active_race(race_name: str) -> str:
|
||||||
race_name = unquote(race_name)
|
race_name = unquote(race_name)
|
||||||
model = TemplateModel()
|
model = TemplateModel()
|
||||||
return render_template("enter.jinja",
|
return render_template("enter.jinja",
|
||||||
@ -190,7 +190,7 @@ def result_active_race(race_name: str):
|
|||||||
|
|
||||||
|
|
||||||
@app.route("/result-enter/<result_race_name>", methods=["POST"])
|
@app.route("/result-enter/<result_race_name>", methods=["POST"])
|
||||||
def result_enter_post(result_race_name: str):
|
def result_enter_post(result_race_name: str) -> Response:
|
||||||
result_race_name = unquote(result_race_name)
|
result_race_name = unquote(result_race_name)
|
||||||
pxxs: List[str] = request.form.getlist("pxxdrivers")
|
pxxs: List[str] = request.form.getlist("pxxdrivers")
|
||||||
dnfs: List[str] = request.form.getlist("dnf-drivers")
|
dnfs: List[str] = request.form.getlist("dnf-drivers")
|
||||||
@ -200,7 +200,7 @@ def result_enter_post(result_race_name: str):
|
|||||||
pxxs_dict: Dict[str, str] = {str(position + 1): driver for position, driver in enumerate(pxxs)}
|
pxxs_dict: Dict[str, str] = {str(position + 1): driver for position, driver in enumerate(pxxs)}
|
||||||
dnfs_dict: Dict[str, str] = {str(position + 1): driver for position, driver in enumerate(pxxs) if driver in dnfs}
|
dnfs_dict: Dict[str, str] = {str(position + 1): driver for position, driver in enumerate(pxxs) if driver in dnfs}
|
||||||
|
|
||||||
raceresult: RaceResult | None = RaceResult.query.filter_by(race_name=result_race_name).first()
|
raceresult: RaceResult | None = db.session.query(RaceResult).filter_by(race_name=result_race_name).first()
|
||||||
|
|
||||||
if raceresult is None:
|
if raceresult is None:
|
||||||
raceresult = RaceResult()
|
raceresult = RaceResult()
|
||||||
@ -212,7 +212,7 @@ def result_enter_post(result_race_name: str):
|
|||||||
raceresult.excluded_driver_names = excludes
|
raceresult.excluded_driver_names = excludes
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
race: Race | None = Race.query.filter_by(name=result_race_name).first()
|
race: Race | None = db.session.query(Race).filter_by(name=result_race_name).first()
|
||||||
if race is None:
|
if race is None:
|
||||||
print("Error: Can't redirect to /enter/<GrandPrix> because race couldn't be found")
|
print("Error: Can't redirect to /enter/<GrandPrix> because race couldn't be found")
|
||||||
return redirect(f"/result/Current")
|
return redirect(f"/result/Current")
|
||||||
@ -221,7 +221,7 @@ def result_enter_post(result_race_name: str):
|
|||||||
|
|
||||||
|
|
||||||
@app.route("/user")
|
@app.route("/user")
|
||||||
def user_root():
|
def user_root() -> str:
|
||||||
users: List[User] = User.query.all()
|
users: List[User] = User.query.all()
|
||||||
|
|
||||||
return render_template("users.jinja",
|
return render_template("users.jinja",
|
||||||
@ -229,14 +229,14 @@ def user_root():
|
|||||||
|
|
||||||
|
|
||||||
@app.route("/user-add", methods=["POST"])
|
@app.route("/user-add", methods=["POST"])
|
||||||
def user_add_post():
|
def user_add_post() -> Response:
|
||||||
username: str | None = request.form.get("select-add-user")
|
username: str | None = request.form.get("select-add-user")
|
||||||
|
|
||||||
if username is None or len(username) == 0:
|
if username is None or len(username) == 0:
|
||||||
print(f"Not adding user, since no username was received")
|
print(f"Not adding user, since no username was received")
|
||||||
return user_root()
|
return redirect("/user")
|
||||||
|
|
||||||
if len(User.query.filter_by(name=username).all()) > 0:
|
if len(db.session.query(User).filter_by(name=username).all()) > 0:
|
||||||
print(f"Not adding user {username}: Already exists!")
|
print(f"Not adding user {username}: Already exists!")
|
||||||
return redirect("/user")
|
return redirect("/user")
|
||||||
|
|
||||||
@ -249,7 +249,7 @@ def user_add_post():
|
|||||||
|
|
||||||
|
|
||||||
@app.route("/user-delete", methods=["POST"])
|
@app.route("/user-delete", methods=["POST"])
|
||||||
def user_delete_post():
|
def user_delete_post() -> Response:
|
||||||
username = request.form.get("select-delete-user")
|
username = request.form.get("select-delete-user")
|
||||||
|
|
||||||
if username is None or len(username) == 0:
|
if username is None or len(username) == 0:
|
||||||
|
61
model.py
61
model.py
@ -1,13 +1,12 @@
|
|||||||
import json
|
import json
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from typing import List, Dict
|
from typing import Any, List, Dict
|
||||||
from urllib.parse import quote
|
from urllib.parse import quote
|
||||||
|
|
||||||
from flask_sqlalchemy import SQLAlchemy
|
from flask_sqlalchemy import SQLAlchemy
|
||||||
from sqlalchemy import Integer, String, DateTime, ForeignKey
|
from sqlalchemy import Integer, String, DateTime, ForeignKey
|
||||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||||
|
|
||||||
db = SQLAlchemy()
|
db: SQLAlchemy = SQLAlchemy()
|
||||||
|
|
||||||
####################################
|
####################################
|
||||||
# Static Data (Defined in Backend) #
|
# Static Data (Defined in Backend) #
|
||||||
@ -21,7 +20,7 @@ class Race(db.Model):
|
|||||||
"""
|
"""
|
||||||
__tablename__ = "race"
|
__tablename__ = "race"
|
||||||
|
|
||||||
def from_csv(self, row):
|
def from_csv(self, row: List[str]):
|
||||||
self.name = str(row[0])
|
self.name = str(row[0])
|
||||||
self.number = int(row[1])
|
self.number = int(row[1])
|
||||||
self.date = datetime.strptime(row[2], "%Y-%m-%d")
|
self.date = datetime.strptime(row[2], "%Y-%m-%d")
|
||||||
@ -44,7 +43,7 @@ class Team(db.Model):
|
|||||||
"""
|
"""
|
||||||
__tablename__ = "team"
|
__tablename__ = "team"
|
||||||
|
|
||||||
def from_csv(self, row):
|
def from_csv(self, row: List[str]):
|
||||||
self.name = str(row[0])
|
self.name = str(row[0])
|
||||||
return self
|
return self
|
||||||
|
|
||||||
@ -58,7 +57,7 @@ class Driver(db.Model):
|
|||||||
"""
|
"""
|
||||||
__tablename__ = "driver"
|
__tablename__ = "driver"
|
||||||
|
|
||||||
def from_csv(self, row):
|
def from_csv(self, row: List[str]):
|
||||||
self.name = str(row[0])
|
self.name = str(row[0])
|
||||||
self.abbr = str(row[1])
|
self.abbr = str(row[1])
|
||||||
self.team_name = str(row[2])
|
self.team_name = str(row[2])
|
||||||
@ -86,11 +85,11 @@ class User(db.Model):
|
|||||||
__tablename__ = "user"
|
__tablename__ = "user"
|
||||||
__csv_header__ = ["name"]
|
__csv_header__ = ["name"]
|
||||||
|
|
||||||
def from_csv(self, row):
|
def from_csv(self, row: List[str]):
|
||||||
self.name = str(row[0])
|
self.name = str(row[0])
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def to_csv(self):
|
def to_csv(self) -> List[Any]:
|
||||||
return [
|
return [
|
||||||
self.name
|
self.name
|
||||||
]
|
]
|
||||||
@ -111,14 +110,14 @@ class RaceResult(db.Model):
|
|||||||
__allow_unmapped__ = True # TODO: Used for json conversion, move this to some other class instead
|
__allow_unmapped__ = True # TODO: Used for json conversion, move this to some other class instead
|
||||||
__csv_header__ = ["race_name", "pxx_driver_names_json", "dnf_driver_names_json", "excluded_driver_names_json"]
|
__csv_header__ = ["race_name", "pxx_driver_names_json", "dnf_driver_names_json", "excluded_driver_names_json"]
|
||||||
|
|
||||||
def from_csv(self, row):
|
def from_csv(self, row: List[str]):
|
||||||
self.race_name = str(row[0])
|
self.race_name = str(row[0])
|
||||||
self.pxx_driver_names_json = str(row[1])
|
self.pxx_driver_names_json = str(row[1])
|
||||||
self.dnf_driver_names_json = str(row[2])
|
self.dnf_driver_names_json = str(row[2])
|
||||||
self.excluded_driver_names_json = str(row[3])
|
self.excluded_driver_names_json = str(row[3])
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def to_csv(self):
|
def to_csv(self) -> List[Any]:
|
||||||
return [
|
return [
|
||||||
self.race_name,
|
self.race_name,
|
||||||
self.pxx_driver_names_json,
|
self.pxx_driver_names_json,
|
||||||
@ -166,7 +165,7 @@ class RaceResult(db.Model):
|
|||||||
if self._pxx_drivers is None:
|
if self._pxx_drivers is None:
|
||||||
self._pxx_drivers = dict()
|
self._pxx_drivers = dict()
|
||||||
for position, driver_name in self.pxx_driver_names.items():
|
for position, driver_name in self.pxx_driver_names.items():
|
||||||
driver = Driver.query.filter_by(name=driver_name).first()
|
driver: Driver | None = db.session.query(Driver).filter_by(name=driver_name).first()
|
||||||
if driver is None:
|
if driver is None:
|
||||||
raise Exception(f"Error: Couldn't find driver with id {driver_name}")
|
raise Exception(f"Error: Couldn't find driver with id {driver_name}")
|
||||||
|
|
||||||
@ -176,11 +175,11 @@ class RaceResult(db.Model):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def pxx_drivers_values(self) -> List[Driver]:
|
def pxx_drivers_values(self) -> List[Driver]:
|
||||||
drivers: List[Driver] = []
|
drivers: List[Driver] = list()
|
||||||
|
|
||||||
# I don't know what order dict.values() etc. will return...
|
# I don't know what order dict.values() etc. will return...
|
||||||
for position in range(1, 21):
|
for position in range(1, 21):
|
||||||
drivers += [self.pxx_drivers[str(position)]]
|
drivers.append(self.pxx_drivers[str(position)])
|
||||||
|
|
||||||
return drivers
|
return drivers
|
||||||
|
|
||||||
@ -189,7 +188,7 @@ class RaceResult(db.Model):
|
|||||||
if self._dnf_drivers is None:
|
if self._dnf_drivers is None:
|
||||||
self._dnf_drivers = dict()
|
self._dnf_drivers = dict()
|
||||||
for position, driver_name in self.dnf_driver_names.items():
|
for position, driver_name in self.dnf_driver_names.items():
|
||||||
driver = Driver.query.filter_by(name=driver_name).first()
|
driver: Driver | None = db.session.query(Driver).filter_by(name=driver_name).first()
|
||||||
if driver is None:
|
if driver is None:
|
||||||
raise Exception(f"Error: Couldn't find driver with id {driver_name}")
|
raise Exception(f"Error: Couldn't find driver with id {driver_name}")
|
||||||
|
|
||||||
@ -200,13 +199,13 @@ class RaceResult(db.Model):
|
|||||||
@property
|
@property
|
||||||
def excluded_drivers(self) -> List[Driver]:
|
def excluded_drivers(self) -> List[Driver]:
|
||||||
if self._excluded_drivers is None:
|
if self._excluded_drivers is None:
|
||||||
self._excluded_drivers = []
|
self._excluded_drivers = list()
|
||||||
for driver_name in self.excluded_driver_names:
|
for driver_name in self.excluded_driver_names:
|
||||||
driver = Driver.query.filter_by(name=driver_name).first()
|
driver: Driver | None = db.session.query(Driver).filter_by(name=driver_name).first()
|
||||||
if driver is None:
|
if driver is None:
|
||||||
raise Exception(f"Error: Couldn't find driver with id {driver_name}")
|
raise Exception(f"Error: Couldn't find driver with id {driver_name}")
|
||||||
|
|
||||||
self._excluded_drivers += [driver]
|
self._excluded_drivers.append(driver)
|
||||||
|
|
||||||
return self._excluded_drivers
|
return self._excluded_drivers
|
||||||
|
|
||||||
@ -230,14 +229,14 @@ class RaceGuess(db.Model):
|
|||||||
__tablename__ = "raceguess"
|
__tablename__ = "raceguess"
|
||||||
__csv_header__ = ["user_name", "race_name", "pxx_driver_name", "dnf_driver_name"]
|
__csv_header__ = ["user_name", "race_name", "pxx_driver_name", "dnf_driver_name"]
|
||||||
|
|
||||||
def from_csv(self, row):
|
def from_csv(self, row: List[str]):
|
||||||
self.user_name = str(row[0])
|
self.user_name = str(row[0])
|
||||||
self.race_name = str(row[1])
|
self.race_name = str(row[1])
|
||||||
self.pxx_driver_name = str(row[2])
|
self.pxx_driver_name = str(row[2])
|
||||||
self.dnf_driver_name = str(row[3])
|
self.dnf_driver_name = str(row[3])
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def to_csv(self):
|
def to_csv(self) -> List[Any]:
|
||||||
return [
|
return [
|
||||||
self.user_name,
|
self.user_name,
|
||||||
self.race_name,
|
self.race_name,
|
||||||
@ -265,12 +264,12 @@ class TeamWinners(db.Model):
|
|||||||
__allow_unmapped__ = True
|
__allow_unmapped__ = True
|
||||||
__csv_header__ = ["user_name", "teamwinner_driver_names_json"]
|
__csv_header__ = ["user_name", "teamwinner_driver_names_json"]
|
||||||
|
|
||||||
def from_csv(self, row):
|
def from_csv(self, row: List[str]):
|
||||||
self.user_name = str(row[0])
|
self.user_name = str(row[0])
|
||||||
self.teamwinner_driver_names_json = str(row[1])
|
self.teamwinner_driver_names_json = str(row[1])
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def to_csv(self):
|
def to_csv(self) -> List[Any]:
|
||||||
return [
|
return [
|
||||||
self.user_name,
|
self.user_name,
|
||||||
self.teamwinner_driver_names_json
|
self.teamwinner_driver_names_json
|
||||||
@ -294,13 +293,13 @@ class TeamWinners(db.Model):
|
|||||||
@property
|
@property
|
||||||
def teamwinners(self) -> List[Driver]:
|
def teamwinners(self) -> List[Driver]:
|
||||||
if self._teamwinner_drivers is None:
|
if self._teamwinner_drivers is None:
|
||||||
self._teamwinner_drivers = []
|
self._teamwinner_drivers = list()
|
||||||
for driver_name in self.teamwinner_driver_names:
|
for driver_name in self.teamwinner_driver_names:
|
||||||
driver = Driver.query.filter_by(name=driver_name).first()
|
driver: Driver | None = db.session.query(Driver).filter_by(name=driver_name).first()
|
||||||
if driver is None:
|
if driver is None:
|
||||||
raise Exception(f"Error: Couldn't find driver with id {driver_name}")
|
raise Exception(f"Error: Couldn't find driver with id {driver_name}")
|
||||||
|
|
||||||
self._teamwinner_drivers += [driver]
|
self._teamwinner_drivers.append(driver)
|
||||||
|
|
||||||
return self._teamwinner_drivers
|
return self._teamwinner_drivers
|
||||||
|
|
||||||
@ -313,12 +312,12 @@ class PodiumDrivers(db.Model):
|
|||||||
__allow_unmapped__ = True
|
__allow_unmapped__ = True
|
||||||
__csv_header__ = ["user_name", "podium_driver_names_json"]
|
__csv_header__ = ["user_name", "podium_driver_names_json"]
|
||||||
|
|
||||||
def from_csv(self, row):
|
def from_csv(self, row: List[str]):
|
||||||
self.user_name = str(row[0])
|
self.user_name = str(row[0])
|
||||||
self.podium_driver_names_json = str(row[1])
|
self.podium_driver_names_json = str(row[1])
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def to_csv(self):
|
def to_csv(self) -> List[Any]:
|
||||||
return [
|
return [
|
||||||
self.user_name,
|
self.user_name,
|
||||||
self.podium_driver_names_json
|
self.podium_driver_names_json
|
||||||
@ -342,13 +341,13 @@ class PodiumDrivers(db.Model):
|
|||||||
@property
|
@property
|
||||||
def podium_drivers(self) -> List[Driver]:
|
def podium_drivers(self) -> List[Driver]:
|
||||||
if self._podium_drivers is None:
|
if self._podium_drivers is None:
|
||||||
self._podium_drivers = []
|
self._podium_drivers = list()
|
||||||
for driver_name in self.podium_driver_names:
|
for driver_name in self.podium_driver_names:
|
||||||
driver = Driver.query.filter_by(name=driver_name).first()
|
driver: Driver | None = db.session.query(Driver).filter_by(name=driver_name).first()
|
||||||
if driver is None:
|
if driver is None:
|
||||||
raise Exception(f"Error: Couldn't find driver with id {driver_name}")
|
raise Exception(f"Error: Couldn't find driver with id {driver_name}")
|
||||||
|
|
||||||
self._podium_drivers += [driver]
|
self._podium_drivers.append(driver)
|
||||||
|
|
||||||
return self._podium_drivers
|
return self._podium_drivers
|
||||||
|
|
||||||
@ -362,7 +361,7 @@ class SeasonGuess(db.Model):
|
|||||||
"overtake_driver_name", "dnf_driver_name", "gained_driver_name", "lost_driver_name",
|
"overtake_driver_name", "dnf_driver_name", "gained_driver_name", "lost_driver_name",
|
||||||
"team_winners_id", "podium_drivers_id"]
|
"team_winners_id", "podium_drivers_id"]
|
||||||
|
|
||||||
def from_csv(self, row):
|
def from_csv(self, row: List[str]):
|
||||||
self.user_name = str(row[0]) # Also used as foreign key for teamwinners + podiumdrivers
|
self.user_name = str(row[0]) # Also used as foreign key for teamwinners + podiumdrivers
|
||||||
self.hot_take = str(row[1])
|
self.hot_take = str(row[1])
|
||||||
self.p2_team_name = str(row[2])
|
self.p2_team_name = str(row[2])
|
||||||
@ -374,7 +373,7 @@ class SeasonGuess(db.Model):
|
|||||||
self.podium_drivers_id = str(row[8])
|
self.podium_drivers_id = str(row[8])
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def to_csv(self):
|
def to_csv(self) -> List[Any]:
|
||||||
return [
|
return [
|
||||||
self.user_name,
|
self.user_name,
|
||||||
self.hot_take,
|
self.hot_take,
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
from typing import List, Iterable, Callable, TypeVar, Dict, overload, Any
|
from typing import List, Iterable, Callable, TypeVar, Dict, overload
|
||||||
|
|
||||||
from sqlalchemy import desc
|
from sqlalchemy import desc
|
||||||
|
from model import User, RaceResult, RaceGuess, Race, Driver, Team, SeasonGuess, db
|
||||||
from model import User, RaceResult, RaceGuess, Race, Driver, Team, SeasonGuess
|
|
||||||
|
|
||||||
_T = TypeVar("_T")
|
_T = TypeVar("_T")
|
||||||
|
|
||||||
@ -73,7 +71,7 @@ class TemplateModel:
|
|||||||
Returns a list of all users in the database.
|
Returns a list of all users in the database.
|
||||||
"""
|
"""
|
||||||
if self._all_users is None:
|
if self._all_users is None:
|
||||||
self._all_users = User.query.all()
|
self._all_users = db.session.query(User).all()
|
||||||
|
|
||||||
return self._all_users
|
return self._all_users
|
||||||
|
|
||||||
@ -106,7 +104,7 @@ class TemplateModel:
|
|||||||
Returns a list of all race results in the database, in descending order (most recent first).
|
Returns a list of all race results in the database, in descending order (most recent first).
|
||||||
"""
|
"""
|
||||||
if self._all_race_results is None:
|
if self._all_race_results is None:
|
||||||
self._all_race_results = RaceResult.query.join(RaceResult.race).order_by(desc(Race.number)).all()
|
self._all_race_results = db.session.query(RaceResult).join(RaceResult.race).order_by(desc(Race.number)).all()
|
||||||
|
|
||||||
return self._all_race_results
|
return self._all_race_results
|
||||||
|
|
||||||
@ -122,26 +120,26 @@ class TemplateModel:
|
|||||||
Returns a list of all race guesses in the database.
|
Returns a list of all race guesses in the database.
|
||||||
"""
|
"""
|
||||||
if self._all_race_guesses is None:
|
if self._all_race_guesses is None:
|
||||||
self._all_race_guesses = RaceGuess.query.all()
|
self._all_race_guesses = db.session.query(RaceGuess).all()
|
||||||
|
|
||||||
return self._all_race_guesses
|
return self._all_race_guesses
|
||||||
|
|
||||||
@overload
|
@overload
|
||||||
def race_guesses_by(self, *, user_name) -> List[RaceGuess]:
|
def race_guesses_by(self, *, user_name: str) -> List[RaceGuess]:
|
||||||
"""
|
"""
|
||||||
Returns a list of all race guesses made by a specific user.
|
Returns a list of all race guesses made by a specific user.
|
||||||
"""
|
"""
|
||||||
return self.race_guesses_by(user_name=user_name)
|
return self.race_guesses_by(user_name=user_name)
|
||||||
|
|
||||||
@overload
|
@overload
|
||||||
def race_guesses_by(self, *, race_name) -> List[RaceGuess]:
|
def race_guesses_by(self, *, race_name: str) -> List[RaceGuess]:
|
||||||
"""
|
"""
|
||||||
Returns a list of all race guesses made for a specific race.
|
Returns a list of all race guesses made for a specific race.
|
||||||
"""
|
"""
|
||||||
return self.race_guesses_by(race_name=race_name)
|
return self.race_guesses_by(race_name=race_name)
|
||||||
|
|
||||||
@overload
|
@overload
|
||||||
def race_guesses_by(self, *, user_name, race_name) -> RaceGuess | None:
|
def race_guesses_by(self, *, user_name: str, race_name: str) -> RaceGuess | None:
|
||||||
"""
|
"""
|
||||||
Returns a single race guess by a specific user for a specific race, or None, if this guess doesn't exist.
|
Returns a single race guess by a specific user for a specific race, or None, if this guess doesn't exist.
|
||||||
"""
|
"""
|
||||||
@ -154,7 +152,7 @@ class TemplateModel:
|
|||||||
"""
|
"""
|
||||||
return self.race_guesses_by()
|
return self.race_guesses_by()
|
||||||
|
|
||||||
def race_guesses_by(self, *, user_name=None, race_name=None) -> RaceGuess | List[RaceGuess] | Dict[str, Dict[str, RaceGuess]] | None:
|
def race_guesses_by(self, *, user_name: str | None = None, race_name: str | None = None) -> RaceGuess | List[RaceGuess] | Dict[str, Dict[str, RaceGuess]] | None:
|
||||||
# List of all guesses by a single user
|
# List of all guesses by a single user
|
||||||
if user_name is not None and race_name is None:
|
if user_name is not None and race_name is None:
|
||||||
predicate: Callable[[RaceGuess], bool] = lambda guess: guess.user_name == user_name
|
predicate: Callable[[RaceGuess], bool] = lambda guess: guess.user_name == user_name
|
||||||
@ -187,12 +185,12 @@ class TemplateModel:
|
|||||||
|
|
||||||
def all_season_guesses(self) -> List[SeasonGuess]:
|
def all_season_guesses(self) -> List[SeasonGuess]:
|
||||||
if self._all_season_guesses is None:
|
if self._all_season_guesses is None:
|
||||||
self._all_season_guesses = SeasonGuess.query.all()
|
self._all_season_guesses = db.session.query(SeasonGuess).all()
|
||||||
|
|
||||||
return self._all_season_guesses
|
return self._all_season_guesses
|
||||||
|
|
||||||
@overload
|
@overload
|
||||||
def season_guesses_by(self, *, user_name) -> SeasonGuess:
|
def season_guesses_by(self, *, user_name: str) -> SeasonGuess:
|
||||||
"""
|
"""
|
||||||
Returns the season guess made by a specific user.
|
Returns the season guess made by a specific user.
|
||||||
"""
|
"""
|
||||||
@ -205,7 +203,7 @@ class TemplateModel:
|
|||||||
"""
|
"""
|
||||||
return self.season_guesses_by()
|
return self.season_guesses_by()
|
||||||
|
|
||||||
def season_guesses_by(self, *, user_name=None) -> SeasonGuess | Dict[str, SeasonGuess] | None:
|
def season_guesses_by(self, *, user_name: str | None = None) -> SeasonGuess | Dict[str, SeasonGuess] | None:
|
||||||
if user_name is not None:
|
if user_name is not None:
|
||||||
predicate: Callable[[SeasonGuess], bool] = lambda guess: guess.user_name == user_name
|
predicate: Callable[[SeasonGuess], bool] = lambda guess: guess.user_name == user_name
|
||||||
return find_single_or_none(predicate, self.all_season_guesses())
|
return find_single_or_none(predicate, self.all_season_guesses())
|
||||||
@ -226,7 +224,7 @@ class TemplateModel:
|
|||||||
Returns a list of all races in the database.
|
Returns a list of all races in the database.
|
||||||
"""
|
"""
|
||||||
if self._all_races is None:
|
if self._all_races is None:
|
||||||
self._all_races = Race.query.order_by(desc(Race.number)).all()
|
self._all_races = db.session.query(Race).order_by(desc(Race.number)).all()
|
||||||
|
|
||||||
return self._all_races
|
return self._all_races
|
||||||
|
|
||||||
@ -248,7 +246,7 @@ class TemplateModel:
|
|||||||
Returns a list of all teams in the database.
|
Returns a list of all teams in the database.
|
||||||
"""
|
"""
|
||||||
if self._all_teams is None:
|
if self._all_teams is None:
|
||||||
self._all_teams = Team.query.all()
|
self._all_teams = db.session.query(Team).all()
|
||||||
|
|
||||||
return self._all_teams
|
return self._all_teams
|
||||||
|
|
||||||
@ -257,7 +255,7 @@ class TemplateModel:
|
|||||||
Returns a list of all drivers in the database, including the NONE driver.
|
Returns a list of all drivers in the database, including the NONE driver.
|
||||||
"""
|
"""
|
||||||
if self._all_drivers is None:
|
if self._all_drivers is None:
|
||||||
self._all_drivers = Driver.query.all()
|
self._all_drivers = db.session.query(Driver).all()
|
||||||
|
|
||||||
return self._all_drivers
|
return self._all_drivers
|
||||||
|
|
||||||
@ -269,7 +267,7 @@ class TemplateModel:
|
|||||||
return find_multiple(predicate, self.all_drivers())
|
return find_multiple(predicate, self.all_drivers())
|
||||||
|
|
||||||
@overload
|
@overload
|
||||||
def drivers_by(self, *, team_name) -> List[Driver]:
|
def drivers_by(self, *, team_name: str) -> List[Driver]:
|
||||||
"""
|
"""
|
||||||
Returns a list of all drivers driving for a certain team.
|
Returns a list of all drivers driving for a certain team.
|
||||||
"""
|
"""
|
||||||
@ -282,7 +280,7 @@ class TemplateModel:
|
|||||||
"""
|
"""
|
||||||
return self.drivers_by()
|
return self.drivers_by()
|
||||||
|
|
||||||
def drivers_by(self, *, team_name=None) -> List[Driver] | Dict[str, List[Driver]]:
|
def drivers_by(self, *, team_name: str | None = None) -> List[Driver] | Dict[str, List[Driver]]:
|
||||||
if team_name is not None:
|
if team_name is not None:
|
||||||
predicate: Callable[[Driver], bool] = lambda driver: driver.team.name == team_name
|
predicate: Callable[[Driver], bool] = lambda driver: driver.team.name == team_name
|
||||||
return find_multiple(predicate, self.all_drivers_except_none(), 2)
|
return find_multiple(predicate, self.all_drivers_except_none(), 2)
|
||||||
|
@ -146,7 +146,7 @@ P{{ result.race.pxx + 3 }}: {{ result.pxx(3).abbr }}
|
|||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<nav class="navbar fixed-top navbar-expand-lg bg-body-tertiary">
|
<nav class="navbar fixed-top navbar-expand-lg bg-body-tertiary shadow-sm">
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<a class="navbar-brand" href="/race">
|
<a class="navbar-brand" href="/race">
|
||||||
<img src="../static/image/f1_logo.svg" alt="Logo" width="120" height="30"
|
<img src="../static/image/f1_logo.svg" alt="Logo" width="120" height="30"
|
||||||
|
Reference in New Issue
Block a user