-
Notifications
You must be signed in to change notification settings - Fork 58
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Develop #29
base: main
Are you sure you want to change the base?
Develop #29
Changes from 9 commits
0876865
bf796e2
9c25e10
6108bdf
1f375c2
953e098
85ee446
67adcfd
6d7e315
bf35d05
a04009e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
from database import get_db | ||
from fastapi import Depends, Query | ||
from models import MovieModel | ||
from schemas import MovieCreateSchema, MovieUpdateSchema | ||
from sqlalchemy.orm import Session | ||
|
||
|
||
def create_movie(db: Session, movie: MovieCreateSchema): | ||
db_movie = MovieModel(**movie.dict()) | ||
db.add(db_movie) | ||
db.commit() | ||
db.refresh(db_movie) | ||
return db_movie | ||
|
||
|
||
def get_movie(movie_id: int, db: Session = Depends(get_db)): | ||
movie = db.query(MovieModel).filter(MovieModel.id == movie_id).first() | ||
return movie | ||
|
||
|
||
def get_movies( | ||
page: int = Query(default=1, ge=1, description="The page number(>= 1)"), | ||
per_page: int = Query(default=10, ge=1, le=20, description="Film quantity at the page (>= 1 и <= 20)"), | ||
db: Session = Depends(get_db) | ||
): | ||
total_items = db.query(MovieModel).count() | ||
offset = (page - 1) * per_page | ||
movies = db.query(MovieModel).order_by(MovieModel.id.desc()).offset(offset).limit(per_page).all() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The |
||
base_url = "/movies/" | ||
prev_page = f"{base_url}?page={page - 1}&per_page={per_page}" if page > 1 else None | ||
next_page = f"{base_url}?page={page + 1}&per_page={per_page}" if offset + per_page < total_items else None | ||
return { | ||
"movies": movies, | ||
"prev_page": prev_page, | ||
"next_page": next_page, | ||
"total_pages": (total_items + per_page - 1) // per_page, | ||
"total_items": total_items, | ||
} | ||
|
||
|
||
def update_movie(db: Session, movie_id: int, movie: MovieUpdateSchema): | ||
db_movie = db.query(MovieModel).filter(MovieModel.id == movie_id).first() | ||
if not db_movie: | ||
return None | ||
db_movie.title = movie.title | ||
db_movie.genre = movie.genre | ||
db_movie.price = movie.price | ||
db.commit() | ||
db.refresh(db_movie) | ||
return db_movie | ||
|
||
|
||
def delete_movie(db: Session, movie_id: int): | ||
db_movie = db.query(MovieModel).filter(MovieModel.id == movie_id).first() | ||
if not db_movie: | ||
return None | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Instead of returning |
||
db.delete(db_movie) | ||
db.commit() | ||
return db_movie |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,61 @@ | ||
from fastapi import APIRouter, Depends, HTTPException, Query | ||
from sqlalchemy.exc import IntegrityError | ||
from sqlalchemy.orm import Session, joinedload | ||
|
||
from src.crud.movies import create_movie, get_movie, get_movies, update_movie, delete_movie | ||
from database import get_db | ||
from database.models import MovieModel, CountryModel, GenreModel, ActorModel, LanguageModel | ||
from fastapi import APIRouter, Depends, HTTPException | ||
from sqlalchemy.orm import Session | ||
|
||
from src.database.models import MovieModel | ||
from src.schemas.movies import MovieReadSchema, MovieCreateSchema, \ | ||
MovieUpdateSchema | ||
|
||
router = APIRouter() | ||
|
||
|
||
# Write your code here | ||
@router.post("/movies/", response_model=MovieReadSchema) | ||
def add_movie(movie: MovieCreateSchema, db: Session = Depends(get_db)): | ||
existing_movie = ( | ||
db.query(MovieModel) | ||
.filter(MovieModel.name == movie.name, MovieModel.date == movie.date) | ||
.first() | ||
) | ||
if existing_movie: | ||
raise HTTPException( | ||
status_code=409, | ||
detail=f"A movie with the name '{movie.name}' and release date '{movie.date}' already exists." | ||
) | ||
if existing_movie is None: | ||
raise HTTPException(status_code=400) | ||
return create_movie(db, movie) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The check for |
||
|
||
|
||
@router.get("/movies/", response_model=list[MovieReadSchema], status_code=200) | ||
def list_movies(db: Session = Depends(get_db)): | ||
db_movie = get_movies(db) | ||
Comment on lines
+18
to
+19
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The |
||
if not db_movie: | ||
Comment on lines
+19
to
+20
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The |
||
raise HTTPException(status_code=404, detail="No movies found for the specified page.") | ||
return db_movie | ||
|
||
|
||
@router.get("/movies/{movie_id}", response_model=MovieReadSchema) | ||
def read_movie(movie_id: int, db: Session = Depends(get_db)): | ||
db_movie = get_movie(db, movie_id) | ||
if not db_movie: | ||
raise HTTPException(status_code=404, detail="Movie with the given ID was not found.") | ||
return db_movie | ||
|
||
|
||
@router.put("/movies/{movie_id}", response_model=MovieReadSchema, status_code=200) | ||
def edit_movie(movie_id: int, movie: MovieUpdateSchema, db: Session = Depends(get_db)): | ||
db_movie = update_movie(db, movie_id, movie) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The |
||
if not db_movie: | ||
raise HTTPException(status_code=404, detail="Movie with the given ID was not found.") | ||
if db_movie is None: | ||
raise HTTPException(status_code=400, detail="Invalid input data.") | ||
return db_movie | ||
|
||
|
||
@router.delete("/movies/{movie_id}", response_model=MovieReadSchema, status_code=204) | ||
def remove_movie(movie_id: int, db: Session = Depends(get_db)): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The |
||
db_movie = delete_movie(db, movie_id) | ||
if not db_movie: | ||
raise HTTPException(status_code=404, detail="Movie with the given ID was not found.") | ||
return db_movie |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,103 @@ | ||
# Write your code here | ||
from datetime import datetime, date, timedelta | ||
from typing import Optional, List | ||
|
||
from pydantic import BaseModel, Field, validator | ||
|
||
|
||
class CountrySchema(BaseModel): | ||
name: str | ||
|
||
|
||
class GenreSchema(BaseModel): | ||
name: str | ||
|
||
|
||
class ActorSchema(BaseModel): | ||
name: str | ||
|
||
|
||
class LanguageSchema(BaseModel): | ||
name: str | ||
|
||
|
||
class MovieBaseSchema(BaseModel): | ||
id: int | ||
name: str | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The |
||
date: datetime.date | ||
score: Optional[float] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use |
||
genre: Optional[str] | ||
overview: Optional[str] | ||
crew: Optional[str] | ||
orig_title: Optional[str] | ||
status: Optional[str] | ||
orig_lang: Optional[str] | ||
budget: Optional[int] | ||
revenue: Optional[float] | ||
country: Optional[str] | ||
|
||
|
||
class MovieCreateSchema(MovieBaseSchema): | ||
title: str = Field(max_length=255, description="Название фильма (не более 255 символов)") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The |
||
release_date: date = Field(description="Дата выхода фильма") | ||
score: int = Field(ge=0, le=100, description="Оценка (0-100)") | ||
budget: int = Field(ge=0, description="Бюджет (не может быть отрицательным)") | ||
revenue: int = Field(ge=0, description="Доход (не может быть отрицательным)") | ||
country: CountrySchema | ||
genres: List[GenreSchema] | ||
actors: List[ActorSchema] | ||
languages: List[LanguageSchema] | ||
|
||
@validator("release_date") | ||
def validate_date(cls, value): | ||
max_date = date.today() + timedelta(days=365) | ||
if value > max_date: | ||
raise ValueError("Дата выхода не может превышать текущую дату более чем на 1 год.") | ||
return value | ||
|
||
|
||
class MovieUpdateSchema(MovieBaseSchema): | ||
score: int = Field(ge=0, le=100, description="Оценка (0-100)") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The |
||
budget: int = Field(ge=0, description="Бюджет (не может быть отрицательным)") | ||
revenue: int = Field(ge=0, description="Доход (не может быть отрицательным)") | ||
|
||
|
||
class MovieReadSchema(MovieBaseSchema): | ||
id: int = Field(ge=0) | ||
genres: List[GenreSchema] | ||
actors: List[ActorSchema] | ||
languages: List[LanguageSchema] | ||
|
||
class Config: | ||
from_attributes = True | ||
|
||
@validator("id") | ||
def validate_id(cls, value): | ||
if movie_id := value: | ||
return movie_id | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The |
||
|
||
class MovieDetailResponseSchema(BaseModel): | ||
id: int | ||
name: str | ||
date: datetime.date | ||
score: Optional[float] | ||
genre: Optional[str] | ||
overview: Optional[str] | ||
crew: Optional[str] | ||
orig_title: Optional[str] | ||
status: Optional[str] | ||
orig_lang: Optional[str] | ||
budget: Optional[int] | ||
revenue: Optional[float] | ||
country: Optional[str] | ||
|
||
class Config: | ||
from_attributes: True | ||
|
||
|
||
class MovieListResponseSchema(BaseModel): | ||
movies: List[MovieDetailResponseSchema] | ||
prev_page: Optional[str] | ||
next_page: Optional[str] | ||
total_pages: int | ||
total_items: int |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
create_movie
function should include a check for duplicate movies based onname
anddate
. If a duplicate is found, it should return a409 Conflict
error with the message: "A movie with the name '{name}' and release date '{date}' already exists." .