Browse Source

building articles

master
Mohsen Taba 4 months ago
parent
commit
ff0cde6c63
  1. 265
      apps/article/management/commands/populate_article.py
  2. 3
      entrypoint.sh
  3. BIN
      seeds/images/articl3.jpg

265
apps/article/management/commands/populate_article.py

@ -1,11 +1,11 @@
import os
import random
from django.core.management.base import BaseCommand
from django.core.files import File
from django.core.files.base import ContentFile
from django.conf import settings
from django.db import transaction
from django.utils.text import slugify
# REPLACE 'apps.article.models' WITH YOUR ACTUAL APP PATH
# REPLACE WITH YOUR ACTUAL APP PATHS
from apps.article.models import (
Article,
ArticleCategory,
@ -17,107 +17,182 @@ from apps.article.models import (
)
class Command(BaseCommand):
help = 'Seeds 25 articles with categories, collections, and structured content.'
help = 'Seeds 25 rich Islamic articles (No Atomic Transaction).'
def handle(self, *args, **kwargs):
self.stdout.write('Seeding Articles...')
self.stdout.write('--- Starting Rich Article Seeding ---')
# 1. Configuration
TOTAL_ARTICLES = 25
# ==========================================
# 1. CONFIGURATION
# ==========================================
TOTAL_ARTICLES_TO_CREATE = 25
CATEGORY_IDS = [6, 7, 8, 9]
CONTENT_SOURCE_IDS = range(13, 24) # IDs 13 to 23
PROTECTED_SLUG = "امام-حسین-ع-از-ولادت-تا-جاودانگی-تحلیلی-بر-مبانی-ق"
IMAGE_DIR = os.path.join(settings.BASE_DIR, 'seeds', 'images')
IMAGE_NAMES = [f'articl{i}.jpg' for i in range(2, 5)]
# 2. Fetch Existing Dependencies
# Explicit file names based on your folder structure
IMAGE_NAMES = ['articl2.jpg', 'articl3.jpg', 'articl4.jpg']
RICH_DATA = [
{
'title_en': 'The Event of Ghadir Khumm: Completion of Religion',
'title_fa': 'واقعه غدیر خم: کمال دین و اتمام نعمت',
'summary': 'An analysis of the sermon of the Prophet (PBUH) at Ghadir Khumm.',
'arabic': 'مَنْ كُنْتُ مَوْلَاهُ فَهَذَا عَلِيٌّ مَوْلَاهُ',
'trans': 'For whomever I am his Master (Mawla), then Ali is his Master.',
'content_body': 'The event of Ghadir is one of the most undeniable historical events in Islam...'
},
{
'title_en': 'Lady Fatimah (SA): The Role Model for Women',
'title_fa': 'حضرت فاطمه زهرا (س): الگوی زنان عالم',
'summary': 'Exploring the virtues of the daughter of the Prophet.',
'arabic': 'فَاطِمَةُ بَضْعَةٌ مِنِّي',
'trans': 'Fatimah is a part of me.',
'content_body': 'Lady Fatimah az-Zahra (SA) is not just a role model for women...'
},
{
'title_en': 'Nahj al-Balagha: The Peak of Eloquence',
'title_fa': 'نهج البلاغه: قله فصاحت و بلاغت',
'summary': 'A look into the sermons of Imam Ali (AS).',
'arabic': 'سَلُونِي قَبْلَ أَنْ تَفْقِدُونِي',
'trans': 'Ask me before you lose me.',
'content_body': 'Nahj al-Balagha contains deep philosophical guidance...'
},
{
'title_en': 'The Significance of Laylat al-Qadr',
'title_fa': 'عظمت شب قدر',
'summary': 'Why is the Night of Power better than a thousand months?',
'arabic': 'إِنَّا أَنزَلْنَاهُ فِي لَيْلَةِ الْقَدْرِ',
'trans': 'Indeed, We sent the Qur\'an down during the Night of Decree.',
'content_body': 'The Night of Qadr is the night where destiny is written...'
},
{
'title_en': 'Imam Mahdi (AJ): The Savior',
'title_fa': 'امام مهدی (عج): منجی بشریت',
'summary': 'The concept of the Awaited One in Islamic eschatology.',
'arabic': 'بَقِيَّتُ اللَّهِ خَيْرٌ لَكُمْ',
'trans': 'The remnant of Allah is better for you.',
'content_body': 'The belief in a savior is universal...'
},
{
'title_en': 'Rights of Parents',
'title_fa': 'حقوق والدین',
'summary': 'Examining the status of parents.',
'arabic': 'وَبِالْوَالِدَيْنِ إِحْسَانًا',
'trans': 'And be good to parents.',
'content_body': 'Respecting parents is placed immediately after worship of God...'
}
]
# ==========================================
# 2. CLEANUP
# ==========================================
self.stdout.write("Cleaning old articles (preserving protected one)...")
deleted_count, _ = Article.objects.exclude(slug=PROTECTED_SLUG).delete()
ArticleCollection.objects.all().delete()
self.stdout.write(self.style.WARNING(f"Deleted {deleted_count} articles."))
# ==========================================
# 3. PREPARE DEPENDENCIES
# ==========================================
categories = list(ArticleCategory.objects.filter(id__in=CATEGORY_IDS))
if not categories:
self.stdout.write(self.style.WARNING(f"Categories with IDs {CATEGORY_IDS} not found. Skipping category assignment."))
# 3. Create 4 New Collections
collection_names = [
("Islamic History", "تاریخ اسلام"),
("Theology & Beliefs", "عقاید و کلام"),
("Ethics & Spirituality", "اخلاق و عرفان"),
("Quran & Hadith", "قرآن و حدیث")
]
collections = []
for i in range(1, 5):
col, created = ArticleCollection.objects.get_or_create(
title=f'Seeded Collection {i}',
defaults={
'slug': f'seeded-collection-{i}',
'summary': f'This is a generated summary for collection {i}',
'display_position': ArticleCollection.DisplayPosition.MIDDLE
}
for en_name, fa_name in collection_names:
col = ArticleCollection.objects.create(
title=en_name,
slug=slugify(en_name),
summary=f'Collection of {en_name}',
display_position=ArticleCollection.DisplayPosition.MIDDLE
)
collections.append(col)
self.stdout.write(self.style.SUCCESS(f'Created/Loaded {len(collections)} collections.'))
# 4. Fetch Source Content for Cloning
# NOTE: Since ArticleContent is a ForeignKey (One-to-Many), we cannot
# link existing content objects to new articles without removing them
# from their old articles. Instead, we will CLONE their data.
source_contents = list(ArticleContent.objects.filter(id__in=CONTENT_SOURCE_IDS))
if not source_contents:
self.stdout.write(self.style.WARNING(f"ArticleContents with IDs 13-23 not found. Creating generic content instead."))
# 5. Main Loop: Create Articles
with transaction.atomic():
for i in range(1, TOTAL_ARTICLES + 1):
title = f'Seeded Article Title {i}'
# Create Article
article = Article.objects.create(
title=title,
description=f'Description for article {i}. Lorem ipsum dolor sit amet.',
content=f'Full content body for article {i}.',
status=True
)
# Assign Thumbnail (Cycle through images 1-5)
img_name = IMAGE_NAMES[(i - 1) % len(IMAGE_NAMES)]
img_path = os.path.join(IMAGE_DIR, img_name)
if os.path.exists(img_path):
# ==========================================
# 4. MAIN CREATION LOOP (NO ATOMIC TRANSACTION)
# ==========================================
self.stdout.write("Starting creation loop...")
for i in range(1, TOTAL_ARTICLES_TO_CREATE + 1):
# Select Data
data = RICH_DATA[(i - 1) % len(RICH_DATA)]
# Construct Unique Data
final_title = f"{data['title_en']} (Vol {i})"
short_slug_base = slugify(data['title_en'])[:30]
unique_slug = f"{short_slug_base}-{i}"
if unique_slug == PROTECTED_SLUG:
unique_slug = f"{unique_slug}-generated"
# 1. Create Article Object
article = Article.objects.create(
title=final_title,
slug=unique_slug,
description=data['summary'],
content=data['content_body'],
status=True
)
# 2. Handle Image
img_name = IMAGE_NAMES[(i - 1) % len(IMAGE_NAMES)]
img_path = os.path.join(IMAGE_DIR, img_name)
if os.path.exists(img_path):
try:
with open(img_path, 'rb') as f:
article.thumbnail.save(img_name, File(f), save=True)
else:
self.stdout.write(self.style.WARNING(f"Image not found at {img_path}"))
# Assign Categories (Randomly pick 1 or 2)
if categories:
article.categories.add(*random.sample(categories, k=random.randint(1, 2)))
# Assign to Collections (Randomly pick 1)
random_col = random.choice(collections)
ArticleInCollection.objects.create(
article=article,
collection=random_col,
order=i
)
# Create Article Content (Cloning from IDs 13-23 or Generic)
if source_contents:
# Pick a random template from the requested IDs
template = random.choice(source_contents)
content_title = f"{template.title} (Copy for Article {i})"
content_body = template.content
else:
content_title = f"Structured Content for Article {i}"
content_body = "This is a section of structured content."
# Create the ArticleContent object linked to this NEW article
ac = ArticleContent.objects.create(
article=article,
title=content_title,
content=content_body,
priority=1
)
# Create nested ContentParts and TextSections
part = ContentPart.objects.create(article_content=ac, order=1)
TextSection.objects.create(
content_part=part,
arabic_text="نص تجريبي باللغة العربية",
translation="Experimental text in English translation",
order=1
)
self.stdout.write(f'Created Article: {article.title}')
self.stdout.write(self.style.SUCCESS(f'Successfully seeded {TOTAL_ARTICLES} articles!'))
file_content = f.read()
# NOTE: If the script hangs here, check Article.save() signals
article.thumbnail.save(img_name, ContentFile(file_content), save=True)
except Exception as e:
self.stdout.write(self.style.ERROR(f"Error saving image for item {i}: {e}"))
else:
self.stdout.write(self.style.WARNING(f"Image missing: {img_path}"))
# 3. Assign Categories
if categories:
article.categories.add(*random.sample(categories, k=random.randint(1, 2)))
# 4. Assign Collection
random_col = random.choice(collections)
ArticleInCollection.objects.create(
article=article,
collection=random_col,
order=i
)
# 5. Create Content Hierarchy
ac = ArticleContent.objects.create(
article=article,
title=data['title_fa'],
content=data['content_body'],
priority=1
)
part = ContentPart.objects.create(article_content=ac, order=1)
TextSection.objects.create(
content_part=part,
arabic_text=data['arabic'],
translation=data['trans'],
order=1
)
TextSection.objects.create(
content_part=part,
arabic_text=f"شرح: {data['title_fa']}",
translation=f"Commentary on {data['title_en']}",
order=2
)
self.stdout.write(f"[{i}/{TOTAL_ARTICLES_TO_CREATE}] Created: {unique_slug}")
self.stdout.write(self.style.SUCCESS(f'Successfully seeded {TOTAL_ARTICLES_TO_CREATE} rich articles.'))

3
entrypoint.sh

@ -7,6 +7,7 @@ python manage.py collectstatic --noinput
# python manage.py populate_books
# python manage.py populate_book_reference
python manage.py populate_refrence_images
# python manage.py populate_refrence_images
python manage.py populate_article
exec "$@"

BIN
seeds/images/articl3.jpg

After

Width: 1192  |  Height: 796  |  Size: 254 KiB

Loading…
Cancel
Save