commit dd0be3e2570817f77ba1839a9ef8a67659eecde3 Author: wowlikon Date: Mon May 26 21:57:57 2025 +0300 init diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..d1b9371 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,10 @@ +FROM python:3.9 + +WORKDIR /code + +COPY requirements.txt ./ +RUN pip install --no-cache-dir -r requirements.txt + +COPY ./app /code/app + +CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"] diff --git a/app/__init__.py b/app/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/database.py b/app/database.py new file mode 100644 index 0000000..827e974 --- /dev/null +++ b/app/database.py @@ -0,0 +1,16 @@ +from sqlmodel import create_engine, SQLModel, Session +from dotenv import load_dotenv +import os + +load_dotenv() + +DATABASE_URL = os.getenv("DATABASE_URL") +if not DATABASE_URL: + raise ValueError("DATABASE_URL environment variable is not set") + +engine = create_engine(DATABASE_URL, echo=True) +SQLModel.metadata.create_all(engine) + +def get_session(): + with Session(engine) as session: + yield session diff --git a/app/main.py b/app/main.py new file mode 100644 index 0000000..402b1e0 --- /dev/null +++ b/app/main.py @@ -0,0 +1,42 @@ +from fastapi import FastAPI +from sqlmodel import SQLModel, Session, select +from .database import engine +from .models import Author, Book + +app = FastAPI() + +@app.on_event("startup") +def on_startup(): + SQLModel.metadata.create_all(engine) + +@app.get("/") +async def read_root(): + return {"message": "Hello, FastAPI with SQLModel and PostgreSQL!"} + +@app.post("/authors/") +def create_author(author: Author): + with Session(engine) as session: + session.add(author) + session.commit() + session.refresh(author) + return author + +@app.get("/authors/") +def read_authors(): + with Session(engine) as session: + authors = session.exec(select(Author)).all() + return authors + +@app.post("/books/") +def create_book(book: Book): + with Session(engine) as session: + session.add(book) + session.commit() + session.refresh(book) + return book + +@app.get("/books/") +def read_books(): + with Session(engine) as session: + books = session.exec(select(Book)).all() + return books diff --git a/app/models.py b/app/models.py new file mode 100644 index 0000000..2257560 --- /dev/null +++ b/app/models.py @@ -0,0 +1,18 @@ +from typing import Optional, List +from sqlmodel import SQLModel, Field, Relationship + +class AuthorBookLink(SQLModel, table=True): + author_id: int | None = Field(default=None, foreign_key="author.id", primary_key=True) + book_id: int | None = Field(default=None, foreign_key="book.id", primary_key=True) + +class Author(SQLModel, table=True): + id: Optional[int] = Field(primary_key=True, index=True) + name: str + + books: List["Book"] = Relationship(back_populates="authors", link_model=AuthorBookLink) + +class Book(SQLModel, table=True): + id: Optional[int] = Field(primary_key=True, index=True) + title: str + description: str + authors: List[Author] = Relationship(back_populates="books", link_model=AuthorBookLink) diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..69ba43a --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,23 @@ +services: + db: + image: postgres:15-alpine + environment: + POSTGRES_USER: ${POSTGRES_USER} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} + POSTGRES_DB: ${POSTGRES_DB} + ports: + - "5432:5432" + volumes: + - postgres_data:/var/lib/postgresql/data + + web: + build: . + ports: + - "8000:8000" + environment: + DATABASE_URL: postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB} + depends_on: + - db + +volumes: + postgres_data: diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..b7f81a5 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,5 @@ +fastapi +uvicorn[standard] +sqlmodel +psycopg2-binary +python-dotenv