Browse Source
Add management commands for category and collection seeding
Add management commands for category and collection seeding
- Introduced a new command to evenly distribute source types across existing HadisCategory instances. - Added a command to seed categories and collections in the library, relating existing books to them. - Enhanced HadisCategory model to allow Unicode in slugs through a migration. - Updated Nginx configuration to include a new location for proxying requests to a FastAPI agent.master
5 changed files with 139 additions and 1 deletions
-
42apps/hadis/management/commands/category_fix.py
-
19apps/hadis/migrations/0005_alter_hadiscategory_slug.py
-
2apps/hadis/models/category.py
-
66apps/library/management/commands/seed_category_collection.py
-
11nginx/dovodi.conf
@ -0,0 +1,42 @@ |
|||
from django.core.management.base import BaseCommand |
|||
from django.db import transaction |
|||
from apps.hadis.models import HadisCategory |
|||
|
|||
class Command(BaseCommand): |
|||
help = 'توزیع متعادل انواع منابع (Source Types) بین تمام دستهبندیهای موجود' |
|||
|
|||
def handle(self, *args, **options): |
|||
self.stdout.write(self.style.WARNING('--- در حال بهروزرسانی انواع منابع ---')) |
|||
|
|||
# دریافت تمام گزینههای موجود در SourceType |
|||
source_choices = [choice[0] for choice in HadisCategory.SourceType.choices] |
|||
num_choices = len(source_choices) |
|||
|
|||
# دریافت تمام دستهبندیها به ترتیب شناسه یا ترتیب دلخواه |
|||
categories = HadisCategory.objects.all().order_by('id') |
|||
total_count = categories.count() |
|||
|
|||
if total_count == 0: |
|||
self.stdout.write(self.style.ERROR('هیچ دستهبندی یافت نشد.')) |
|||
return |
|||
|
|||
updated_count = 0 |
|||
|
|||
with transaction.atomic(): |
|||
for index, category in enumerate(categories): |
|||
# انتخاب نوع منبع به صورت چرخشی |
|||
# این کار باعث میشود اگر ۱۲۰ مورد دارید، به هر نوع منبع دقیقاً ۲۴ مورد برسد |
|||
new_source = source_choices[index % num_choices] |
|||
|
|||
category.source_type = new_source |
|||
# استفاده از update_fields برای افزایش سرعت و جلوگیری از اجرای سیگنالهای اضافی در صورت تمایل |
|||
category.save(update_fields=['source_type']) |
|||
updated_count += 1 |
|||
|
|||
self.stdout.write(self.style.SUCCESS(f'✓ عملیات با موفقیت انجام شد.')) |
|||
self.stdout.write(self.style.SUCCESS(f'تعداد {updated_count} دستهبندی بهروزرسانی شدند.')) |
|||
|
|||
# نمایش آمار نهایی برای اطمینان از تعادل |
|||
for source in source_choices: |
|||
count = HadisCategory.objects.filter(source_type=source).count() |
|||
self.stdout.write(f" - {source}: {count} مورد") |
|||
@ -0,0 +1,19 @@ |
|||
# Generated by Django 4.2.27 on 2026-01-28 10:31 |
|||
|
|||
from django.db import migrations, models |
|||
|
|||
|
|||
class Migration(migrations.Migration): |
|||
dependencies = [ |
|||
("hadis", "0004_alter_hadiscollection_thumbnail_and_more"), |
|||
] |
|||
|
|||
operations = [ |
|||
migrations.AlterField( |
|||
model_name="hadiscategory", |
|||
name="slug", |
|||
field=models.SlugField( |
|||
allow_unicode=True, blank=True, max_length=255, null=True |
|||
), |
|||
), |
|||
] |
|||
@ -0,0 +1,66 @@ |
|||
import random |
|||
from django.core.management.base import BaseCommand |
|||
from django.db import transaction |
|||
from apps.library.models import Book, Category, BookCollection |
|||
|
|||
class Command(BaseCommand): |
|||
help = 'Seeds categories and collections and relates all existing books to them.' |
|||
|
|||
def handle(self, *args, **options): |
|||
self.stdout.write(self.style.WARNING('--- Starting Library Relation Seeding ---')) |
|||
|
|||
with transaction.atomic(): |
|||
# 1. CREATE CATEGORIES (10 Instances) |
|||
categories_data = [ |
|||
'Classic Literature', 'Dystopian Fiction', 'Modern Philosophy', |
|||
'Historical Mystery', 'Self-Improvement', 'Biographical Memoir', |
|||
'Fantasy & Adventure', 'Social Science', 'Science & Technology', |
|||
'Religious Studies' |
|||
] |
|||
|
|||
category_objs = [] |
|||
for title in categories_data: |
|||
cat, created = Category.objects.get_or_create(title=title) |
|||
category_objs.append(cat) |
|||
if created: |
|||
self.stdout.write(f"Created Category: {title}") |
|||
|
|||
# 2. CREATE COLLECTIONS (5 Instances) |
|||
collections_data = [ |
|||
{'title': 'Editor\'s Choice 2026', 'pos': BookCollection.DisplayPosition.PINNED}, |
|||
{'title': 'Most Downloaded This Month', 'pos': BookCollection.DisplayPosition.PINNED}, |
|||
{'title': 'New Arrivals', 'pos': BookCollection.DisplayPosition.MIDDLE}, |
|||
{'title': 'Essential Reading List', 'pos': BookCollection.DisplayPosition.MIDDLE}, |
|||
{'title': 'Summer Recommendations', 'pos': BookCollection.DisplayPosition.MIDDLE}, |
|||
] |
|||
|
|||
collection_objs = [] |
|||
for item in collections_data: |
|||
col, created = BookCollection.objects.get_or_create( |
|||
title=item['title'], |
|||
defaults={'display_position': item['pos'], 'pin_top': True} |
|||
) |
|||
collection_objs.append(col) |
|||
if created: |
|||
self.stdout.write(f"Created Collection: {item['title']}") |
|||
|
|||
# 3. RELATE BOOKS |
|||
books = Book.objects.all() |
|||
if not books.exists(): |
|||
self.stdout.write(self.style.ERROR('No books found! Please run the book population script first.')) |
|||
return |
|||
|
|||
self.stdout.write(self.style.SUCCESS(f'Processing {books.count()} books...')) |
|||
|
|||
for book in books: |
|||
# Rule: Every book must have at least 3 categories |
|||
# We pick 3 to 4 random categories to ensure variety |
|||
selected_cats = random.sample(category_objs, k=random.randint(3, 4)) |
|||
book.categories.set(selected_cats) |
|||
|
|||
# Rule: Every book must be in 1 or 2 collections |
|||
selected_cols = random.sample(collection_objs, k=random.randint(1, 2)) |
|||
book.collections.set(selected_cols) |
|||
|
|||
self.stdout.write(self.style.SUCCESS('--- Seeding Completed Successfully ---')) |
|||
self.stdout.write(f'Summary: {len(category_objs)} Categories, {len(collection_objs)} Collections applied to {books.count()} books.') |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue