Compare commits

...
3 Commits
5 changed files with 50 additions and 23 deletions
+1 -1
View File
@@ -1,3 +1,3 @@
.venv .venv
/.idea/ /.idea/
/database.db /api/database.db
+2
View File
@@ -0,0 +1,2 @@
SQLITE_FILE_NAME=database.db
DATABASE_URL=sqlite:///database.db
+42 -18
View File
@@ -1,28 +1,37 @@
import datetime import datetime
from fastapi import FastAPI from fastapi import FastAPI
from fastapi.encoders import jsonable_encoder
from sqlalchemy.exc import IntegrityError, DataError
from sqlmodel import Session, SQLModel, create_engine, select from sqlmodel import Session, SQLModel, create_engine, select
from contextlib import asynccontextmanager from contextlib import asynccontextmanager
from api.models import Car, FuelItem from api.models import Car, FuelItem
from pydantic_settings import BaseSettings, SettingsConfigDict
from fastapi.responses import JSONResponse
sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}" class Settings(BaseSettings):
database_url: str = ""
sqlite_file_name: str = ""
model_config = SettingsConfigDict(env_file=".env")
settings = Settings()
database_url = settings.database_url
connect_args = { connect_args = {
"check_same_thread": False "check_same_thread": False
} }
engine = create_engine(sqlite_url, echo=True, connect_args=connect_args) engine = create_engine(database_url, echo=True, connect_args=connect_args)
def create_db_and_tables(): def create_db_and_tables():
SQLModel.metadata.create_all(engine) SQLModel.metadata.create_all(engine)
@asynccontextmanager def fill_database():
async def lifespan(app: FastAPI):
# startup
create_db_and_tables()
car = Car(id_string="Auto 1") car = Car(id_string="Auto 1")
with Session(engine) as session: with Session(engine) as session:
session.add(car) session.add(car)
@@ -37,19 +46,38 @@ async def lifespan(app: FastAPI):
session.add(fill_item) session.add(fill_item)
session.commit() session.commit()
session.refresh(fill_item) session.refresh(fill_item)
# noinspection PyUnusedLocal
@asynccontextmanager
async def lifespan(actual_app: FastAPI):
# startup
create_db_and_tables()
try:
fill_database()
except IntegrityError as e:
print(e)
yield yield
app = FastAPI(lifespan=lifespan) app = FastAPI(lifespan=lifespan)
def save_object(obj):
with Session(engine) as session:
try:
session.add(obj)
session.commit()
session.refresh(obj)
return obj
except IntegrityError|DataError as e:
content = jsonable_encoder({"message": e})
return JSONResponse(content=content, status_code=400)
@app.post("/cars/") @app.post("/cars/")
def create_cars(car: Car): def create_cars(car: Car):
with Session(engine) as session: return save_object(car)
session.add(car)
session.commit()
session.refresh(car)
return car
@app.get("/cars/") @app.get("/cars/")
@@ -61,11 +89,7 @@ def read_cars():
@app.post("/fill_items/") @app.post("/fill_items/")
def create_cars(fill_item: FuelItem): def create_cars(fill_item: FuelItem):
with Session(engine) as session: return save_object(fill_item)
session.add(fill_item)
session.commit()
session.refresh(fill_item)
return fill_item
@app.get("/fill_items/") @app.get("/fill_items/")
+3 -3
View File
@@ -5,12 +5,12 @@ from sqlmodel import Field, SQLModel
class Car(SQLModel, table=True): class Car(SQLModel, table=True):
id: int | None = Field(default=None, primary_key=True) id: int | None = Field(default=None, primary_key=True)
id_string: str = Field(nullable=False, index=True) id_string: str = Field(nullable=False, index=True, unique=True)
class FuelItem(SQLModel, table=True): class FuelItem(SQLModel, table=True):
id: int | None = Field(default=None, primary_key=True) id: int | None = Field(default=None, primary_key=True)
car_id: int | None = Field(default=None, foreign_key="car.id") car_id: int | None = Field(default=None, foreign_key="car.id", unique_items=True)
date: datetime.date = Field(nullable=False, index=True) date: datetime.date = Field(nullable=False, index=True, unique_items=True)
odometer_reading: float = Field(nullable=False) odometer_reading: float = Field(nullable=False)
fuel_fill: float = Field(nullable=False) fuel_fill: float = Field(nullable=False)
+2 -1
View File
@@ -7,7 +7,8 @@ uvicorn==0.38.0
idna==3.11 idna==3.11
pydantic==2.12.* pydantic==2.12.*
pydantic_core==2.41.* pydantic_core==2.41.*
pydantic_settings==2.11.*
sniffio==1.3.* sniffio==1.3.*
starlette==0.48.* starlette==0.49.*
typing-inspection==0.4.* typing-inspection==0.4.*
typing_extensions==4.15.* typing_extensions==4.15.*