diff --git a/apps/hadis/management/commands/category_fix.py b/apps/hadis/management/commands/category_fix.py new file mode 100644 index 0000000..e4d03f0 --- /dev/null +++ b/apps/hadis/management/commands/category_fix.py @@ -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} مورد") \ No newline at end of file diff --git a/apps/hadis/migrations/0005_alter_hadiscategory_slug.py b/apps/hadis/migrations/0005_alter_hadiscategory_slug.py new file mode 100644 index 0000000..efbd2bf --- /dev/null +++ b/apps/hadis/migrations/0005_alter_hadiscategory_slug.py @@ -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 + ), + ), + ] diff --git a/apps/hadis/models/category.py b/apps/hadis/models/category.py index c648f94..53686d4 100644 --- a/apps/hadis/models/category.py +++ b/apps/hadis/models/category.py @@ -76,7 +76,7 @@ class HadisCategory(MPTTModel): description = models.JSONField(default = list , verbose_name=_('Description')) order = models.IntegerField(default=0, verbose_name=_('order')) xmind_file = models.FileField(upload_to='hadis/xmind_files/', verbose_name=_('xmind file'), null=True, blank=True) - slug = models.SlugField(max_length=255, null=True, blank=True) + slug = models.SlugField(max_length=255, null=True, blank=True,allow_unicode=True) content_type = None language = None language_id = None diff --git a/apps/library/management/commands/seed_category_collection.py b/apps/library/management/commands/seed_category_collection.py new file mode 100644 index 0000000..c3b91a5 --- /dev/null +++ b/apps/library/management/commands/seed_category_collection.py @@ -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.') \ No newline at end of file diff --git a/nginx/dovodi.conf b/nginx/dovodi.conf index d260ba4..f967936 100644 --- a/nginx/dovodi.conf +++ b/nginx/dovodi.conf @@ -14,6 +14,17 @@ server { proxy_read_timeout 600s; # ========== Django Admin Paths (باید قبل از location / باشند) ========== + + # Add this inside the 'server' block of the existing config + + location /agent/ { + proxy_pass http://88.99.212.243:8098; # The port of your FastAPI Agent + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + # با prefix زبانی location /en/dovoodi/ {