""" Django Management Command: populate_books This command creates 20 book objects with related categories and collections, including thumbnails and a dummy PDF file. Usage: python manage.py populate_books """ from django.core.management.base import BaseCommand from django.utils.text import slugify from apps.library.models import Book, Category, BookCollection from dj_language.models import Language import random from django.conf import settings import os from django.core.files import File # Import File wrapper class Command(BaseCommand): help = 'Create 20 book objects with categories, collections, and a PDF file' def handle(self, *args, **options): # 1. DELETE OLD DATA self.stdout.write(self.style.WARNING('Deleting existing books...')) deleted_count = Book.objects.all().delete()[0] self.stdout.write(self.style.SUCCESS(f'✓ Deleted {deleted_count} existing books')) # 2. SETUP PATHS base_dir = settings.BASE_DIR # Image Paths seeds_images_path = os.path.join(base_dir, 'seeds', 'images') image_filenames = [ 'lib-book1.png', 'lib-book2.png', 'lib-book3.png', 'lib-book4.png' ] # PDF Path pdf_path = os.path.join(base_dir, 'seeds', 'pdf', 'e-book.pdf') # Check if PDF exists before starting if not os.path.exists(pdf_path): self.stdout.write(self.style.ERROR(f'CRITICAL: PDF not found at {pdf_path}')) return # 3. GET OR CREATE LANGUAGE language, created = Language.objects.get_or_create( code='en', defaults={'name': 'English'} ) # 4. DATA DEFINITION book_data = [ { 'title': 'To Kill a Mockingbird', 'slogan': 'A powerful story of racial injustice and childhood innocence', 'summary_title': 'Classic American Literature', 'summary': 'Harper Lee\'s timeless novel about courage and morality', 'description': 'Set in the 1930s, this novel explores themes of racism, justice, and moral growth through the eyes of a young girl.', 'publisher': 'J.B. Lippincott & Co.', 'year_of_publication': '1960', 'author': 'Harper Lee', 'isbn': '978-0061120084', 'numnber_of_volume': '1', 'main_themes': ['racism', 'justice', 'childhood', 'morality'], 'notable_works': ['Pulitzer Prize Winner', 'American Classic'], 'pages_count': '376', 'file_type': 'pdf', }, { 'title': 'Pride and Prejudice', 'slogan': 'A witty romance of manners and marriage', 'summary_title': 'Jane Austen\'s Masterpiece', 'summary': 'Elizabeth Bennet navigates love, reputation, and society', 'description': 'This beloved novel follows the spirited Elizabeth Bennet as she deals with issues of manners, upbringing, morality, and marriage.', 'publisher': 'T. Egerton', 'year_of_publication': '1813', 'author': 'Jane Austen', 'isbn': '978-0141439518', 'numnber_of_volume': '1', 'main_themes': ['romance', 'society', 'marriage', 'class'], 'notable_works': ['British Literature', 'Social Commentary'], 'pages_count': '432', 'file_type': 'pdf', }, { 'title': 'The Great Gatsby', 'slogan': 'The American Dream in the Jazz Age', 'summary_title': 'F. Scott Fitzgerald\'s Classic', 'summary': 'A tale of wealth, love, and the American Dream', 'description': 'Set in the summer of 1922, this novel explores the lives of wealthy socialites and their obsession with status and love.', 'publisher': 'Charles Scribner\'s Sons', 'year_of_publication': '1925', 'author': 'F. Scott Fitzgerald', 'isbn': '978-0743273565', 'numnber_of_volume': '1', 'main_themes': ['wealth', 'love', 'american dream', 'jazz age'], 'notable_works': ['Modern Classic', 'American Literature'], 'pages_count': '180', 'file_type': 'pdf', }, { 'title': '1984', 'slogan': 'A dystopian vision of totalitarian control', 'summary_title': 'George Orwell\'s Warning', 'summary': 'Big Brother is watching in this chilling dystopia', 'description': 'In a totalitarian future where truth is manipulated and privacy is nonexistent, Winston Smith begins to question the regime.', 'publisher': 'Secker & Warburg', 'year_of_publication': '1949', 'author': 'George Orwell', 'isbn': '978-0451524935', 'numnber_of_volume': '1', 'main_themes': ['totalitarianism', 'surveillance', 'freedom', 'truth'], 'notable_works': ['Dystopian Fiction', 'Political Satire'], 'pages_count': '328', 'file_type': 'pdf', }, { 'title': 'The Catcher in the Rye', 'slogan': 'A teenager\'s journey through alienation and identity', 'summary_title': 'J.D. Salinger\'s Coming-of-Age Story', 'summary': 'Holden Caulfield\'s honest and raw narration of teenage angst', 'description': 'Sixteen-year-old Holden Caulfield has been expelled from yet another school and wanders New York City in a state of alienation.', 'publisher': 'Little, Brown and Company', 'year_of_publication': '1951', 'author': 'J.D. Salinger', 'isbn': '978-0316769488', 'numnber_of_volume': '1', 'main_themes': ['adolescence', 'alienation', 'identity', 'innocence'], 'notable_works': ['Coming-of-Age', 'American Literature'], 'pages_count': '277', 'file_type': 'pdf', }, { 'title': 'Harry Potter and the Philosopher\'s Stone', 'slogan': 'A young wizard\'s magical adventure begins', 'summary_title': 'J.K. Rowling\'s Magical World', 'summary': 'Harry discovers he\'s a wizard and attends Hogwarts School', 'description': 'Orphaned Harry Potter discovers on his 11th birthday that he is a wizard and begins his magical education at Hogwarts.', 'publisher': 'Bloomsbury', 'year_of_publication': '1997', 'author': 'J.K. Rowling', 'isbn': '978-0747532699', 'numnber_of_volume': '1', 'main_themes': ['magic', 'friendship', 'courage', 'good vs evil'], 'notable_works': ['Fantasy Series', 'Children\'s Literature'], 'pages_count': '223', 'file_type': 'pdf', }, { 'title': 'The Lord of the Rings: The Fellowship of the Ring', 'slogan': 'An epic tale of adventure and heroism', 'summary_title': 'J.R.R. Tolkien\'s Masterpiece', 'summary': 'Frodo\'s quest to destroy the One Ring', 'description': 'In Middle-earth, the Dark Lord Sauron seeks the One Ring to conquer all. A fellowship forms to prevent this catastrophe.', 'publisher': 'George Allen & Unwin', 'year_of_publication': '1954', 'author': 'J.R.R. Tolkien', 'isbn': '978-0547928210', 'numnber_of_volume': '1', 'main_themes': ['adventure', 'friendship', 'courage', 'destiny'], 'notable_works': ['Epic Fantasy', 'World Building'], 'pages_count': '423', 'file_type': 'pdf', }, { 'title': 'The Alchemist', 'slogan': 'Follow your dreams and listen to your heart', 'summary_title': 'Paulo Coelho\'s Inspirational Tale', 'summary': 'A shepherd boy\'s journey to find his personal legend', 'description': 'Santiago, an Andalusian shepherd boy, dreams of finding a worldly treasure and embarks on a journey of self-discovery.', 'publisher': 'HarperOne', 'year_of_publication': '1988', 'author': 'Paulo Coelho', 'isbn': '978-0061122415', 'numnber_of_volume': '1', 'main_themes': ['dreams', 'destiny', 'spirituality', 'journey'], 'notable_works': ['Inspirational Fiction', 'Self-Discovery'], 'pages_count': '208', 'file_type': 'pdf', }, { 'title': 'The Da Vinci Code', 'slogan': 'A thriller that uncovers ancient secrets', 'summary_title': 'Dan Brown\'s Mystery Thriller', 'summary': 'Robert Langdon races to solve a murder mystery', 'description': 'Harvard symbologist Robert Langdon becomes involved in a murder mystery that reveals secrets about the Holy Grail.', 'publisher': 'Doubleday', 'year_of_publication': '2003', 'author': 'Dan Brown', 'isbn': '978-0385504201', 'numnber_of_volume': '1', 'main_themes': ['mystery', 'conspiracy', 'religion', 'history'], 'notable_works': ['Thriller', 'Bestseller'], 'pages_count': '454', 'file_type': 'pdf', }, { 'title': 'Sapiens: A Brief History of Humankind', 'slogan': 'The story of our species from ancient times to modern day', 'summary_title': 'Yuval Noah Harari\'s Evolutionary History', 'summary': 'How Homo sapiens became Earth\'s dominant species', 'description': 'This book explores the history of humankind from the Stone Age to the modern age, examining how we came to dominate Earth.', 'publisher': 'Harper', 'year_of_publication': '2014', 'author': 'Yuval Noah Harari', 'isbn': '978-0062316097', 'numnber_of_volume': '1', 'main_themes': ['history', 'evolution', 'civilization', 'humanity'], 'notable_works': ['Non-fiction', 'Anthropology'], 'pages_count': '443', 'file_type': 'pdf', }, { 'title': 'Educated', 'slogan': 'A memoir of survival and education', 'summary_title': 'Tara Westover\'s Life Story', 'summary': 'A woman\'s quest for knowledge despite her isolated upbringing', 'description': 'Tara Westover grew up in a survivalist family in rural Idaho and fought to educate herself against all odds.', 'publisher': 'Random House', 'year_of_publication': '2018', 'author': 'Tara Westover', 'isbn': '978-0399590504', 'numnber_of_volume': '1', 'main_themes': ['education', 'family', 'survival', 'identity'], 'notable_works': ['Memoir', 'Education'], 'pages_count': '334', 'file_type': 'pdf', }, { 'title': 'Atomic Habits', 'slogan': 'Small changes, remarkable results', 'summary_title': 'James Clear\'s Guide to Better Habits', 'summary': 'How to build good habits and break bad ones', 'description': 'This book reveals how tiny changes in your daily habits can lead to remarkable transformation in your life.', 'publisher': 'Avery', 'year_of_publication': '2018', 'author': 'James Clear', 'isbn': '978-0735211292', 'numnber_of_volume': '1', 'main_themes': ['habits', 'productivity', 'self-improvement', 'psychology'], 'notable_works': ['Self-Help', 'Psychology'], 'pages_count': '320', 'file_type': 'pdf', }, { 'title': 'The Psychology of Money', 'slogan': 'Timeless lessons on wealth, greed, and happiness', 'summary_title': 'Morgan Housel\'s Financial Wisdom', 'summary': 'Understanding the strange ways people think about money', 'description': 'This book explores the psychology behind our financial decisions and how our behavior often defies logic.', 'publisher': 'Harriman House', 'year_of_publication': '2020', 'author': 'Morgan Housel', 'isbn': '978-0857197689', 'numnber_of_volume': '1', 'main_themes': ['finance', 'psychology', 'behavior', 'wealth'], 'notable_works': ['Finance', 'Psychology'], 'pages_count': '256', 'file_type': 'pdf', }, { 'title': 'Thinking, Fast and Slow', 'slogan': 'The groundbreaking investigation of how we think', 'summary_title': 'Daniel Kahneman\'s Cognitive Psychology', 'summary': 'How our minds work in two different modes', 'description': 'Nobel Prize winner Daniel Kahneman explores the two systems that drive how we think: fast, intuitive thinking and slow, deliberate thinking.', 'publisher': 'Farrar, Straus and Giroux', 'year_of_publication': '2011', 'author': 'Daniel Kahneman', 'isbn': '978-0374533557', 'numnber_of_volume': '1', 'main_themes': ['psychology', 'decision-making', 'cognitive bias', 'behavior'], 'notable_works': ['Psychology', 'Nobel Prize'], 'pages_count': '499', 'file_type': 'pdf', }, { 'title': 'The Silent Patient', 'slogan': 'A woman refuses to speak after committing murder', 'summary_title': 'Alex Michaelides\' Psychological Thriller', 'summary': 'A psychotherapist becomes obsessed with his patient\'s silence', 'description': 'Alicia Berenson\'s refusal to speak after allegedly murdering her husband becomes the ultimate mystery for psychotherapist Theo Faber.', 'publisher': 'Celadon Books', 'year_of_publication': '2019', 'author': 'Alex Michaelides', 'isbn': '978-1250301697', 'numnber_of_volume': '1', 'main_themes': ['mystery', 'psychology', 'silence', 'obsession'], 'notable_works': ['Thriller', 'Psychological Fiction'], 'pages_count': '336', 'file_type': 'pdf', }, { 'title': 'The Midnight Library', 'slogan': 'Between life and death, every choice matters', 'summary_title': 'Matt Haig\'s Philosophical Fiction', 'summary': 'A woman gets to live out different versions of her life', 'description': 'Between life and death, Nora Seed finds herself in a library where she can try out different lives she might have lived.', 'publisher': 'Canongate Books', 'year_of_publication': '2020', 'author': 'Matt Haig', 'isbn': '978-0525559474', 'numnber_of_volume': '1', 'main_themes': ['life choices', 'regret', 'possibility', 'self-discovery'], 'notable_works': ['Philosophical Fiction', 'Contemporary'], 'pages_count': '288', 'file_type': 'pdf', }, { 'title': 'Where the Crawdads Sing', 'slogan': 'A mystery wrapped in a coming-of-age story', 'summary_title': 'Delia Owens\' Natural Mystery', 'summary': 'A young woman raised by the marsh becomes a suspect in a murder', 'description': 'Kya Clark, the "Marsh Girl," becomes a suspect in a murder while living in isolation in the North Carolina marshes.', 'publisher': 'G.P. Putnam\'s Sons', 'year_of_publication': '2018', 'author': 'Delia Owens', 'isbn': '978-0735219090', 'numnber_of_volume': '1', 'main_themes': ['nature', 'isolation', 'mystery', 'coming-of-age'], 'notable_works': ['Literary Fiction', 'Mystery'], 'pages_count': '384', 'file_type': 'pdf', }, { 'title': 'The Seven Husbands of Evelyn Hugo', 'slogan': 'A reclusive Hollywood icon tells her story', 'summary_title': 'Taylor Jenkins Reid\'s Glamorous Tale', 'summary': 'A journalist uncovers the secrets of a legendary star', 'description': 'Reclusive Hollywood icon Evelyn Hugo chooses an unknown journalist to tell her life story and the truth about her seven marriages.', 'publisher': 'Washington Square Press', 'year_of_publication': '2017', 'author': 'Taylor Jenkins Reid', 'isbn': '978-1501139239', 'numnber_of_volume': '1', 'main_themes': ['hollywood', 'secrets', 'identity', 'love'], 'notable_works': ['Historical Fiction', 'Romance'], 'pages_count': '400', 'file_type': 'pdf', }, { 'title': 'Circe', 'slogan': 'The story of the witch from The Odyssey', 'summary_title': 'Madeline Miller\'s Mythological Tale', 'summary': 'A mortal woman becomes a goddess and discovers her power', 'description': 'Circe, daughter of the sun god Helios, is banished to an island where she hones her witchcraft and encounters legendary figures.', 'publisher': 'Little, Brown and Company', 'year_of_publication': '2018', 'author': 'Madeline Miller', 'isbn': '978-0316556347', 'numnber_of_volume': '1', 'main_themes': ['mythology', 'power', 'identity', 'transformation'], 'notable_works': ['Mythological Fiction', 'Feminism'], 'pages_count': '393', 'file_type': 'pdf', }, { 'title': 'Normal People', 'slogan': 'A story of first love and complicated friendship', 'summary_title': 'Sally Rooney\'s Contemporary Romance', 'summary': 'Two young people navigate love and connection', 'description': 'Marianne and Connell\'s relationship evolves from high school classmates to university students, exploring themes of love, class, and mental health.', 'publisher': 'Faber & Faber', 'year_of_publication': '2018', 'author': 'Sally Rooney', 'isbn': '978-0571334650', 'numnber_of_volume': '1', 'main_themes': ['love', 'friendship', 'class', 'mental health'], 'notable_works': ['Contemporary Fiction', 'Romance'], 'pages_count': '304', 'file_type': 'pdf', }, { 'title': 'The Vanishing Half', 'slogan': 'Twin sisters choose different racial identities', 'summary_title': 'Brit Bennett\'s Family Saga', 'summary': 'The story of twin sisters who grow up to live in two very different worlds', 'description': 'The Vignes twin sisters grow up in a small black community but choose to live in two very different racial worlds—one white and one black.', 'publisher': 'Riverhead Books', 'year_of_publication': '2020', 'author': 'Brit Bennett', 'isbn': '978-0525536963', 'numnber_of_volume': '1', 'main_themes': ['race', 'identity', 'family', 'belonging'], 'notable_works': ['Literary Fiction', 'Social Commentary'], 'pages_count': '352', 'file_type': 'pdf', }, ] # 5. CREATE NEW DATA created_books = [] for idx, book_info in enumerate(book_data): try: slug = slugify(book_info['title']) # Create the book instance (WITHOUT the image/file first) book = Book( title=book_info['title'], slug=slug, slogan=book_info['slogan'], summary_title=book_info['summary_title'], summary=book_info['summary'], description=book_info['description'], publisher=book_info['publisher'], year_of_publication=book_info['year_of_publication'], author=book_info['author'], isbn=book_info['isbn'], numnber_of_volume=book_info['numnber_of_volume'], language=language, main_themes=book_info['main_themes'], notable_works=book_info['notable_works'], pages_count=book_info['pages_count'], file_type=book_info['file_type'], status=True, pin=True, ) # HANDLE THE IMAGE img_name = image_filenames[idx % len(image_filenames)] img_full_path = os.path.join(seeds_images_path, img_name) if os.path.exists(img_full_path): with open(img_full_path, 'rb') as f: # Copy to media folder book.thumbnail.save(img_name, File(f), save=False) else: self.stdout.write(self.style.WARNING(f"Image not found: {img_full_path}")) # HANDLE THE PDF (NEW LOGIC) # We rename the PDF to match the slug to ensure unique filenames in media pdf_filename = f"{slug}.pdf" if os.path.exists(pdf_path): with open(pdf_path, 'rb') as pdf_f: # Copy to media folder book.book_file.save(pdf_filename, File(pdf_f), save=False) # Now save the book to DB book.save() created_books.append(book) self.stdout.write(self.style.SUCCESS(f'✓ Created: {book.title}')) except Exception as e: self.stdout.write(self.style.ERROR(f'Error creating book {book_info["title"]}: {e}')) # 6. RELATIONS category_ids = [1, 2, 3, 4, 15, 16, 17, 18, 19, 20] collection_ids = [1, 2, 3, 4, 5, 6, 13, 14, 15] self.stdout.write(self.style.SUCCESS('Starting relation assignment...')) # Connect books with categories self.stdout.write(self.style.SUCCESS('\nConnecting books to categories...')) for idx, book in enumerate(created_books): try: # Select 2-3 random categories for each book num_categories = random.randint(2, 3) selected_categories = random.sample(category_ids, num_categories) for category_id in selected_categories: try: category = Category.objects.get(id=category_id) book.categories.add(category) except Category.DoesNotExist: self.stdout.write( self.style.WARNING(f' ⚠ Category with ID {category_id} not found') ) self.stdout.write( self.style.SUCCESS(f' ✓ Connected {book.title} to categories') ) except Exception as e: self.stdout.write( self.style.ERROR(f' ✗ Error connecting categories for {book.title}: {str(e)}') ) continue # Connect books with collections self.stdout.write(self.style.SUCCESS('\nConnecting books to collections...')) for idx, book in enumerate(created_books): try: # Select 1-2 random collections for each book num_collections = random.randint(1, 2) selected_collections = random.sample(collection_ids, num_collections) for collection_id in selected_collections: try: collection = BookCollection.objects.get(id=collection_id) book.collections.add(collection) except BookCollection.DoesNotExist: self.stdout.write( self.style.WARNING(f' ⚠ Collection with ID {collection_id} not found') ) self.stdout.write( self.style.SUCCESS(f' ✓ Connected {book.title} to collections') ) except Exception as e: self.stdout.write( self.style.ERROR(f' ✗ Error connecting collections for {book.title}: {str(e)}') ) continue # Summary self.stdout.write(self.style.SUCCESS('\n' + '='*50)) self.stdout.write( self.style.SUCCESS(f'Successfully created {len(created_books)} books!') ) self.stdout.write(self.style.SUCCESS('='*50))