
- Enhance character model with additional fields - Create relationship between anime and characters - Implement character search functionality - Create Alembic migration for character table - Add sample character data for seeding - Update README with character endpoint information
227 lines
9.0 KiB
Python
227 lines
9.0 KiB
Python
import logging
|
|
from datetime import date
|
|
|
|
from sqlalchemy.orm import Session
|
|
|
|
from app import crud, schemas
|
|
from app.db.session import SessionLocal
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
# Example genres
|
|
INITIAL_GENRES = [
|
|
{"name": "Action"},
|
|
{"name": "Adventure"},
|
|
{"name": "Comedy"},
|
|
{"name": "Drama"},
|
|
{"name": "Fantasy"},
|
|
{"name": "Horror"},
|
|
{"name": "Mystery"},
|
|
{"name": "Romance"},
|
|
{"name": "Sci-Fi"},
|
|
{"name": "Slice of Life"},
|
|
{"name": "Sports"},
|
|
{"name": "Supernatural"},
|
|
{"name": "Thriller"},
|
|
]
|
|
|
|
# Example anime
|
|
INITIAL_ANIME = [
|
|
{
|
|
"title": "Fullmetal Alchemist: Brotherhood",
|
|
"alternative_titles": "Hagane no Renkinjutsushi: Fullmetal Alchemist",
|
|
"synopsis": "After a horrific alchemy experiment goes wrong in the Elric household, brothers Edward and Alphonse are left in a catastrophic new reality.",
|
|
"episodes": 64,
|
|
"status": "Finished Airing",
|
|
"aired_from": date(2009, 4, 5),
|
|
"aired_to": date(2010, 7, 4),
|
|
"duration": "24 min per ep",
|
|
"rating": "R - 17+ (violence & profanity)",
|
|
"score": 9.15,
|
|
"ranked": 1,
|
|
"popularity": 3,
|
|
"studio": "Bones",
|
|
"source": "Manga",
|
|
"genre_ids": [1, 2, 4, 5], # Action, Adventure, Drama, Fantasy
|
|
},
|
|
{
|
|
"title": "Death Note",
|
|
"synopsis": "A high school student discovers a supernatural notebook that has deadly powers. When he discovers that he can kill anyone by writing their name in the notebook, he begins to create his perfect world.",
|
|
"episodes": 37,
|
|
"status": "Finished Airing",
|
|
"aired_from": date(2006, 10, 4),
|
|
"aired_to": date(2007, 6, 27),
|
|
"duration": "23 min per ep",
|
|
"rating": "R - 17+ (violence & profanity)",
|
|
"score": 8.63,
|
|
"ranked": 69,
|
|
"popularity": 1,
|
|
"studio": "Madhouse",
|
|
"source": "Manga",
|
|
"genre_ids": [7, 9, 13], # Mystery, Sci-Fi, Thriller
|
|
},
|
|
{
|
|
"title": "Attack on Titan",
|
|
"alternative_titles": "Shingeki no Kyojin",
|
|
"synopsis": "Centuries ago, mankind was slaughtered to near extinction by monstrous humanoid creatures called Titans, forcing humans to hide in fear behind enormous concentric walls.",
|
|
"episodes": 75,
|
|
"status": "Finished Airing",
|
|
"aired_from": date(2013, 4, 7),
|
|
"aired_to": date(2021, 3, 29),
|
|
"duration": "24 min per ep",
|
|
"rating": "R - 17+ (violence & profanity)",
|
|
"score": 8.51,
|
|
"ranked": 108,
|
|
"popularity": 2,
|
|
"studio": "Wit Studio",
|
|
"source": "Manga",
|
|
"genre_ids": [1, 4, 5], # Action, Drama, Fantasy
|
|
},
|
|
]
|
|
|
|
# Example characters
|
|
INITIAL_CHARACTERS = [
|
|
# Fullmetal Alchemist: Brotherhood characters
|
|
{
|
|
"name": "Edward Elric",
|
|
"role": "Main",
|
|
"description": "The primary protagonist of the series, Edward is a young alchemical prodigy who lost his right arm and left leg after a failed attempt to resurrect his mother. He is the youngest State Alchemist in history, joining the military at the age of 12.",
|
|
"voice_actor": "Romi Park (Japanese), Vic Mignogna (English)",
|
|
"image_url": "https://example.com/edward_elric.jpg",
|
|
"anime_title": "Fullmetal Alchemist: Brotherhood",
|
|
"age": "15-16",
|
|
"gender": "Male",
|
|
"birth_date": date(1899, 2, 3),
|
|
"height": "165 cm (5'5\")",
|
|
"weight": "55 kg (121 lbs)",
|
|
"blood_type": "O",
|
|
"popularity_rank": 1
|
|
},
|
|
{
|
|
"name": "Alphonse Elric",
|
|
"role": "Main",
|
|
"description": "Edward's younger brother, Alphonse lost his entire body in the failed human transmutation experiment. His soul was bound to a suit of armor by Edward, and he seeks to restore his original body.",
|
|
"voice_actor": "Rie Kugimiya (Japanese), Maxey Whitehead (English)",
|
|
"image_url": "https://example.com/alphonse_elric.jpg",
|
|
"anime_title": "Fullmetal Alchemist: Brotherhood",
|
|
"age": "14-15",
|
|
"gender": "Male",
|
|
"birth_date": date(1900, 5, 7),
|
|
"height": "250 cm (in armor)",
|
|
"blood_type": "B",
|
|
"popularity_rank": 2
|
|
},
|
|
# Death Note characters
|
|
{
|
|
"name": "Light Yagami",
|
|
"role": "Main",
|
|
"description": "The main protagonist of Death Note, Light is a high school student who discovers the Death Note. Disgusted with the crime and injustice in the world, he uses the Death Note's power to kill criminals and becomes known as 'Kira'.",
|
|
"voice_actor": "Mamoru Miyano (Japanese), Brad Swaile (English)",
|
|
"image_url": "https://example.com/light_yagami.jpg",
|
|
"anime_title": "Death Note",
|
|
"age": "17-23",
|
|
"gender": "Male",
|
|
"birth_date": date(1986, 2, 28),
|
|
"height": "179 cm (5'10\")",
|
|
"weight": "64 kg (141 lbs)",
|
|
"blood_type": "A",
|
|
"popularity_rank": 3
|
|
},
|
|
{
|
|
"name": "L Lawliet",
|
|
"role": "Main",
|
|
"description": "A mysterious detective with an eccentric personality who takes on the challenge of capturing Kira. Considered the world's greatest detective, L opposes Light in a psychological battle of wits.",
|
|
"voice_actor": "Kappei Yamaguchi (Japanese), Alessandro Juliani (English)",
|
|
"image_url": "https://example.com/l_lawliet.jpg",
|
|
"anime_title": "Death Note",
|
|
"age": "24-25",
|
|
"gender": "Male",
|
|
"birth_date": date(1979, 10, 31),
|
|
"height": "179 cm (5'10\")",
|
|
"weight": "50 kg (110 lbs)",
|
|
"blood_type": "Unknown",
|
|
"popularity_rank": 4
|
|
},
|
|
# Attack on Titan characters
|
|
{
|
|
"name": "Eren Yeager",
|
|
"role": "Main",
|
|
"description": "The main protagonist of Attack on Titan. After his mother is eaten by a Titan, Eren vows to exterminate all Titans. Later, he discovers he has the ability to transform into a Titan.",
|
|
"voice_actor": "Yuki Kaji (Japanese), Bryce Papenbrook (English)",
|
|
"image_url": "https://example.com/eren_yeager.jpg",
|
|
"anime_title": "Attack on Titan",
|
|
"age": "15-19",
|
|
"gender": "Male",
|
|
"birth_date": date(835, 3, 30),
|
|
"height": "170 cm (5'7\")",
|
|
"weight": "63 kg (139 lbs)",
|
|
"blood_type": "Unknown",
|
|
"popularity_rank": 5
|
|
},
|
|
{
|
|
"name": "Mikasa Ackerman",
|
|
"role": "Main",
|
|
"description": "Eren's adoptive sister and one of the main protagonists. After her parents were murdered, Eren saved her life and she has been protective of him ever since. She is considered an exceptionally skilled soldier.",
|
|
"voice_actor": "Yui Ishikawa (Japanese), Trina Nishimura (English)",
|
|
"image_url": "https://example.com/mikasa_ackerman.jpg",
|
|
"anime_title": "Attack on Titan",
|
|
"age": "15-19",
|
|
"gender": "Female",
|
|
"birth_date": date(835, 2, 10),
|
|
"height": "170 cm (5'7\")",
|
|
"weight": "68 kg (150 lbs)",
|
|
"blood_type": "Unknown",
|
|
"popularity_rank": 6
|
|
}
|
|
]
|
|
|
|
|
|
def init_db(db: Session) -> None:
|
|
# Create genres
|
|
for genre_data in INITIAL_GENRES:
|
|
genre = crud.genre.get_by_name(db, name=genre_data["name"])
|
|
if not genre:
|
|
genre_in = schemas.genre.GenreCreate(name=genre_data["name"])
|
|
crud.genre.create(db, obj_in=genre_in)
|
|
logger.info(f"Created genre: {genre_data['name']}")
|
|
|
|
# Create anime
|
|
anime_id_map = {} # Map anime titles to their IDs for character creation
|
|
for anime_data in INITIAL_ANIME:
|
|
anime = crud.anime.get_multi(db, limit=1, skip=0)
|
|
if not anime or all(a.title != anime_data["title"] for a in anime):
|
|
anime_in = schemas.anime.AnimeCreate(**anime_data)
|
|
created_anime = crud.anime.create_with_genres(db, obj_in=anime_in)
|
|
anime_id_map[anime_data["title"]] = created_anime.id
|
|
logger.info(f"Created anime: {anime_data['title']}")
|
|
else:
|
|
# Get the ID for existing anime
|
|
for a in anime:
|
|
if a.title == anime_data["title"]:
|
|
anime_id_map[anime_data["title"]] = a.id
|
|
|
|
# Create characters
|
|
for character_data in INITIAL_CHARACTERS:
|
|
# Get anime ID from title
|
|
anime_title = character_data.pop("anime_title")
|
|
if anime_title in anime_id_map:
|
|
character_data["anime_id"] = anime_id_map[anime_title]
|
|
|
|
# Check if character already exists to avoid duplicates
|
|
existing_characters = crud.character.get_by_anime(db, anime_id=character_data["anime_id"])
|
|
if not any(c.name == character_data["name"] for c in existing_characters):
|
|
character_in = schemas.character.CharacterCreate(**character_data)
|
|
crud.character.create(db, obj_in=character_in)
|
|
logger.info(f"Created character: {character_data['name']}")
|
|
|
|
|
|
def seed_data() -> None:
|
|
"""Seed initial data to the database."""
|
|
logger.info("Seeding initial data to the database")
|
|
db = SessionLocal()
|
|
try:
|
|
init_db(db)
|
|
finally:
|
|
db.close()
|
|
logger.info("Initial data seeded successfully") |