Automated Action bf28ab6f8e Enhance Anime Information API with Advanced Features
- Add proper model relationships for better querying
- Implement character model and endpoints for managing anime characters
- Add advanced filtering options (year, score range, source, studio, etc.)
- Add statistics endpoint for analyzing anime collection
- Include pagination metadata for easier navigation
- Create Alembic migration for the new character model
- Update README with new features and documentation
2025-05-17 21:58:44 +00:00

171 lines
4.6 KiB
Python

from typing import Any, Optional
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
from app import crud, schemas
from app.api import deps
router = APIRouter()
@router.get("/", response_model=schemas.anime.AnimeSearchResults)
def search_anime(
*,
db: Session = Depends(deps.get_db),
title: Optional[str] = None,
genre_id: Optional[int] = None,
status: Optional[str] = None,
year_from: Optional[int] = None,
year_to: Optional[int] = None,
score_min: Optional[float] = None,
score_max: Optional[float] = None,
source: Optional[str] = None,
studio: Optional[str] = None,
sort_by: Optional[str] = None,
sort_order: Optional[str] = "asc",
skip: int = 0,
limit: int = 100,
) -> Any:
"""
Search for anime with advanced filters.
- **title**: Filter by title (partial match)
- **genre_id**: Filter by genre ID
- **status**: Filter by anime status (airing, finished, upcoming)
- **year_from**: Filter by starting year (inclusive)
- **year_to**: Filter by ending year (inclusive)
- **score_min**: Filter by minimum score (inclusive)
- **score_max**: Filter by maximum score (inclusive)
- **source**: Filter by source material (manga, light novel, etc.)
- **studio**: Filter by studio name (partial match)
- **sort_by**: Sort by field (id, title, score, popularity, etc.)
- **sort_order**: Sort order (asc, desc)
- **skip**: Number of items to skip for pagination
- **limit**: Maximum number of items to return
"""
anime = crud.anime.search(
db,
title=title,
genre_id=genre_id,
status=status,
year_from=year_from,
year_to=year_to,
score_min=score_min,
score_max=score_max,
source=source,
studio=studio,
sort_by=sort_by,
sort_order=sort_order,
skip=skip,
limit=limit
)
total = crud.anime.search_count(
db,
title=title,
genre_id=genre_id,
status=status,
year_from=year_from,
year_to=year_to,
score_min=score_min,
score_max=score_max,
source=source,
studio=studio
)
# Calculate pagination metadata
page = skip // limit + 1 if limit > 0 else 1
total_pages = (total + limit - 1) // limit if limit > 0 else 1
has_next = page < total_pages
has_prev = page > 1
return {
"results": anime,
"total": total,
"page": page,
"size": limit,
"pages": total_pages,
"has_next": has_next,
"has_prev": has_prev,
"next_page": page + 1 if has_next else None,
"prev_page": page - 1 if has_prev else None
}
@router.post("/", response_model=schemas.anime.Anime)
def create_anime(
*,
db: Session = Depends(deps.get_db),
anime_in: schemas.anime.AnimeCreate,
) -> Any:
"""
Create new anime.
"""
return crud.anime.create_with_genres(db=db, obj_in=anime_in)
@router.get("/{id}", response_model=schemas.anime.Anime)
def read_anime(
*,
db: Session = Depends(deps.get_db),
id: int,
) -> Any:
"""
Get anime by ID.
"""
anime = crud.anime.get(db=db, id=id)
if not anime:
raise HTTPException(status_code=404, detail="Anime not found")
return anime
@router.put("/{id}", response_model=schemas.anime.Anime)
def update_anime(
*,
db: Session = Depends(deps.get_db),
id: int,
anime_in: schemas.anime.AnimeUpdate,
) -> Any:
"""
Update an anime.
"""
anime = crud.anime.get(db=db, id=id)
if not anime:
raise HTTPException(status_code=404, detail="Anime not found")
anime = crud.anime.update_with_genres(db=db, db_obj=anime, obj_in=anime_in)
return anime
@router.delete("/{id}", response_model=None, status_code=204)
def delete_anime(
*,
db: Session = Depends(deps.get_db),
id: int,
) -> Any:
"""
Delete an anime.
"""
anime = crud.anime.get(db=db, id=id)
if not anime:
raise HTTPException(status_code=404, detail="Anime not found")
crud.anime.remove(db=db, id=id)
return None
@router.get("/statistics", response_model=schemas.anime.AnimeStatistics)
def get_anime_statistics(
db: Session = Depends(deps.get_db),
) -> Any:
"""
Get statistics about the anime collection.
Returns various statistical data including:
- Total anime count
- Average score and episode count
- Distribution by status, source, and studio
- Yearly distribution of releases
- Score distribution
- Top genres
"""
return crud.anime.get_statistics(db=db)