Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .env
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
DB_USER=postgres

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.env нельзя в репозиторий заливать, там обычно секреты хранятся

DB_PASSWORD=12345
DB_HOST=localhost
DB_PORT=5432
DB_NAME=mydatabase
5 changes: 5 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
DB_USER=postgres
DB_PASSWORD=12345
DB_HOST=localhost
DB_PORT=5432
DB_NAME=mydatabase
6 changes: 6 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
FROM python:3.9-slim-buster
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
11 changes: 9 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,12 @@ $ .\myenv\Scripts\activate
```
Так же установить пакеты:
```shell
$ pip install fastapi uvicorn sqlalchemy databases[sqlite] python-dotenv
```
$ pip install fastapi uvicorn sqlalchemy asyncpg psycopg2 pydantic python-dotenv
```
Что бы собрать контейнер и запустить его воспользоваться командами:
```shell
$ docker-compose up --build
$ docker-compose up -d
```

P.s. Для запуска необходим установленный на пк Docker.
14 changes: 14 additions & 0 deletions app/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from pydantic import BaseSettings

class Settings(BaseSettings):
db_user: str
db_password: str
db_host: str
db_port: str
db_name: str

class Config:
env_file = ".env"
env_file_encoding = "utf-8"

settings = Settings()
12 changes: 12 additions & 0 deletions app/database.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
from app.config import settings

# Подключение к базе данных
SQLALCHEMY_DATABASE_URL = f"postgresql://{settings.db_user}:{settings.db_password}@{settings.db_host}:{settings.db_port}/{settings.db_name}"

engine = create_engine(SQLALCHEMY_DATABASE_URL)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)

Base = declarative_base()
16 changes: 0 additions & 16 deletions app/main.py

This file was deleted.

42 changes: 42 additions & 0 deletions app/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
from typing import List
from sqlalchemy import Column, Integer, String, ForeignKey
from sqlalchemy.orm import relationship
from pydantic import BaseModel
from app.database import Base

# Модель студента
class Student(Base):
__tablename__ = 'students'
id = Column(Integer, primary_key=True, index=True)
name = Column(String, nullable=False)
group_id = Column(Integer, ForeignKey('groups.id'))
group = relationship('Group', back_populates='students')

# Модель группы
class Group(Base):
__tablename__ = 'groups'
id = Column(Integer, primary_key=True, index=True)
name = Column(String, nullable=False)
students = relationship('Student', back_populates='group')

# Модель для создания студента
class StudentCreate(BaseModel):
name: str
group_id: int

# Модель для создания группы
class GroupCreate(BaseModel):
name: str

# Модель для ответа с информацией о студенте
class StudentResponse(BaseModel):
id: int
name: str
group_id: int

# Модель для ответа с информацией о группе
class GroupResponse(BaseModel):
id: int
name: str
students: List[StudentResponse]

125 changes: 125 additions & 0 deletions app/routes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
from fastapi import APIRouter, HTTPException, Depends
from sqlalchemy.orm import Session
from app.database import SessionLocal, engine
from app.models import Student, Group, StudentCreate, GroupCreate, StudentResponse, GroupResponse

router = APIRouter()

def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()


# API эндпоинт для создания студента
@router.post("/students/")
def create_student(student: StudentCreate, db: Session = Depends(get_db)):
db_student = Student(name=student.name, group_id=student.group_id)
db.add(db_student)
db.commit()
db.refresh(db_student)
return {"id": db_student.id, "name": db_student.name, "group_id": db_student.group_id}

# API эндпоинт для создания группы
@router.post("/groups/")
def create_group(group: GroupCreate, db: Session = Depends(get_db)):
db_group = Group(name=group.name)
db.add(db_group)
db.commit()
db.refresh(db_group)
return {"id": db_group.id, "name": db_group.name}

# API эндпоинт для получения информации о студенте по его id
@router.get("/students/{student_id}")
def get_student(student_id: int, db: Session = Depends(get_db)):
student = db.query(Student).filter(Student.id == student_id).first()
if not student:
raise HTTPException(status_code=404, detail="Student not found")
return {"id": student.id, "name": student.name, "group_id": student.group_id}

# API эндпоинт для получения информации о группе по ее id
@router.get("/groups/{group_id}")
def get_group(group_id: int, db: Session = Depends(get_db)):
group = db.query(Group).filter(Group.id == group_id).first()
if not group:
raise HTTPException(status_code=404, detail="Group not found")
return {"id": group.id, "name": group.name}

# API эндпоинт для удаления студента
@router.delete("/students/{student_id}")
def delete_student(student_id: int, db: Session = Depends(get_db)):
student = db.query(Student).filter(Student.id == student_id).first()
if not student:
raise HTTPException(status_code=404, detail="Student not found")
db.delete(student)
db.commit()
return {"message": "Student deleted"}

# API эндпоинт для удаления группы
@router.delete("/groups/{group_id}")
def delete_group(group_id: int, db: Session = Depends(get_db)):
group = db.query(Group).filter(Group.id == group_id).first()
if not group:
raise HTTPException(status_code=404, detail="Group not found")
db.delete(group)
db.commit()
return {"message": "Group deleted"}

# API эндпоинт для получения списка студентов
@router.get("/students/")
def get_students(db: Session = Depends(get_db)):
students = db.query(Student).all()
return students

# API эндпоинт для получения списка групп
@router.get("/groups/")
def get_groups(db: Session = Depends(get_db)):
groups = db.query(Group).all()
return groups

# API эндпоинт для добавления студента в группу
@router.post("/groups/{group_id}/students/{student_id}")
def add_student_to_group(group_id: int, student_id: int, db: Session = Depends(get_db)):
group = db.query(Group).filter(Group.id == group_id).first()
student = db.query(Student).filter(Student.id == student_id).first()
if not group:
raise HTTPException(status_code=404, detail="Group not found")
if not student:
raise HTTPException(status_code=404, detail="Student not found")
student.group_id = group_id
db.commit()
return {"message": "Student added to group"}

# API эндпоинт для удаления студента из группы
@router.delete("/groups/{group_id}/students/{student_id}")
def remove_student_from_group(group_id: int, student_id: int, db: Session = Depends(get_db)):
student = db.query(Student).filter(Student.id == student_id).first()
if not student:
raise HTTPException(status_code=404, detail="Student not found")
student.group_id = None
db.commit()
return {"message": "Student removed from group"}

# API эндпоинт для получения всех студентов в группе
@router.get("/groups/{group_id}/students/")
def get_students_in_group(group_id: int, db: Session = Depends(get_db)):
group = db.query(Group).filter(Group.id == group_id).first()
if not group:
raise HTTPException(status_code=404, detail="Group not found")
students = group.students
return students

# API эндпоинт для перевода студента из группы A в группу B
@router.put("/students/{student_id}/move/{group_id}")
def move_student(student_id: int, group_id: int, db: Session = Depends(get_db)):
student = db.query(Student).filter(Student.id == student_id).first()
group = db.query(Group).filter(Group.id == group_id).first()
if not student:
raise HTTPException(status_code=404, detail="Student not found")
if not group:
raise HTTPException(status_code=404, detail="Group not found")
student.group_id = group_id
db.commit()
return {"message": "Student moved to another group"}
28 changes: 28 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
version: '3.8'

services:
db:
image: postgres
restart: always
environment:
POSTGRES_USER: ${DB_USER}
POSTGRES_PASSWORD: ${DB_PASSWORD}
POSTGRES_DB: ${DB_NAME}
ports:
- 5432:5432

app:
build:
context: .
dockerfile: Dockerfile
restart: always
environment:
- DB_USER=${DB_USER}
- DB_PASSWORD=${DB_PASSWORD}
- DB_HOST=localhost
- DB_PORT=5432
- DB_NAME=${DB_NAME}
ports:
- 8000:8000
depends_on:
- db
7 changes: 7 additions & 0 deletions main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from fastapi import FastAPI
from app.routes import router

app = FastAPI()

app.include_router(router, prefix="/api")

7 changes: 7 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
fastapi
uvicorn
sqlalchemy
asyncpg
psycopg2-binary
pydantic
python-dotenv