۱۰. شخصیسازی پنل ادمین (admin.py)
حالا که پنل ادمین رو داریم، بیاید یه کم خوشگلتر و کاربردیترش کنیم. منطق این کار، ساخت یه کلاس سفارشی برای هر مدله که به جنگو میگه اون مدل رو چطور در پنل ادمین نمایش بده.
ما میخوایم لیست پستها در پنل ادمین، اطلاعات بیشتری مثل اسلاگ، نویسنده و وضعیت رو نشون بده. همچنین قابلیت فیلتر کردن و جستجو رو هم بهش اضافه میکنیم.
پرامپت پیشنهادی: «میخوام مدل Post رو در پنل ادمین جنگو شخصیسازی کنم. یه کلاس PostAdmin برام بساز که این قابلیتها رو داشته باشه: - در لیست پستها، فیلدهای title, slug, author, publish, status نمایش داده بشن. - قابلیت فیلتر کردن بر اساس status, created, publish, author وجود داشته باشه. - بشه بر اساس title و body جستجو کرد. - فیلد slug به صورت خودکار از روی title پر بشه. - مرتبسازی پیشفرض بر اساس status و publish باشه.»
هوش مصنوعی کدی شبیه به این رو برای شما تولید میکنه که باید در فایل blog/admin.py قرار بدید:
from django.contrib import admin
from .models import Post
@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
list_display = ['title', 'slug', 'author', 'publish', 'status']
list_filter = ['status', 'created', 'publish', 'author']
search_fields = ['title', 'body']
prepopulated_fields = {'slug': ('title',)}
raw_id_fields = ['author']
date_hierarchy = 'publish'
ordering = ['status', 'publish']
با این چند خط کد ساده، پنل ادمین شما از این رو به اون رو میشه! حالا یه بخش فیلتر، یه نوار جستجو و کلی قابلیت باحال دیگه دارید.
🎬 ویدیوی آموزشی: پنل ادمین جنگو در عمل!
برای اینکه ببینید این تغییرات در عمل چطور پنل ادمین رو متحول میکنه، ویدیوی آموزشی ما رو در یوتیوب ببینید. با کلیک روی دکمه زیر، جادوی پنل ادمین جنگو رو به صورت بصری تجربه کنید! 👇
▶️ تماشای ویدیو در یوتیوب۱۱. کار با QuerySetها و مدیرها
خب، تا اینجا یاد گرفتیم چطور با پنل ادمین به صورت دستی داده وارد کنیم. اما قدرت اصلی جنگو اینه که به ما اجازه میده به صورت برنامهنویسی با دیتابیس کار کنیم. منطق این کار از طریق ORM (Object-Relational Mapper) جنگو انجام میشه.
ORM یعنی چی؟ یعنی ما به جای نوشتن کدهای SQL، با آبجکتهای پایتون کار میکنیم و جنگو خودش پشت پرده اونها رو به SQL تبدیل میکنه. ابزار اصلی ما برای این کار، QuerySet هست. QuerySet یه مجموعه از کوئریهای دیتابیسه که به ما اجازه میده آبجکتها رو از دیتابیس بخونیم، فیلتر کنیم، آپدیت کنیم و حذف کنیم.
برای دسترسی به QuerySetها، از مدیر پیشفرض هر مدل به اسم objects استفاده میکنیم.
ساختن، آپدیت کردن و خوندن آبجکتها
بیاید با چندتا مثال عملی ببینیم چطور میشه با QuerySetها کار کرد. برای این کار، اول شل تعاملی جنگو رو باز میکنیم.
پرامپت پیشنهادی: «دستور باز کردن شل تعاملی جنگو چیه؟»
python manage.py shell
حالا که داخل شل هستیم، میتونیم از هوش مصنوعی بخوایم کدهای لازم رو بهمون بده:
پرامپت پیشنهادی: «با استفاده از ORM جنگو، کدهای پایتون زیر رو برام بنویس: 1. کاربر با یوزرنیم 'admin' رو پیدا کن و تو یه متغیر بریز. 2. یه پست جدید با عنوان 'پست جدید من' بساز و نویسندهاش رو همین کاربر قرار بده. 3. تمام پستهای موجود در دیتابیس رو بهم نشون بده. 4. پستهایی که نویسندهشون کاربر 'admin' هست رو فیلتر کن و نشون بده.»
هوش مصنوعی کدهایی شبیه به این رو به شما میده:
from django.contrib.auth.models import User
from blog.models import Post
# 1. پیدا کردن کاربر
user = User.objects.get(username='admin')
# 2. ساخت پست جدید
post = Post.objects.create(title='پست جدید من',
slug='my-new-post',
body='این متن پست جدید من است.',
author=user)
# 3. نمایش همه پستها
all_posts = Post.objects.all()
print(all_posts)
# 4. فیلتر کردن پستها
admin_posts = Post.objects.filter(author=user)
print(admin_posts)
میبینید؟ بدون حتی یک خط کد SQL، به راحتی با دیتابیس کار کردیم. این قدرت ORM جنگو و QuerySetهاست!
استفاده از جستجوگرهای فیلد (Field Lookups)
قدرت اصلی QuerySetها در فیلتر کردنه. منطق این کار، استفاده از جستجوگرهای فیلد هست. ما با استفاده از دوتا زیرخط (__) بعد از اسم فیلد، به جنگو میگیم که دقیقاً دنبال چی بگرده.
به جای حفظ کردن همه اینها، کافیه منطق کلی رو بفهمید و بعد از هوش مصنوعی بخواید که بر اساس نیازتون، کد دقیق رو بهتون بده.
پرامپت پیشنهادی: «میخوام تو جنگو پستهایی رو پیدا کنم که عنوانشون شامل کلمه 'جنگو' باشه، بدون توجه به حروف بزرگ و کوچیک. QuerySet لازم رو برام بنویس.»
هوش مصنوعی به شما کدی شبیه به این میده:
Post.objects.filter(title__icontains='جنگو')
چندتا از پرکاربردترین جستجوگرها:
__exact: مطابقت دقیق (پیشفرض).__iexact: مطابقت دقیق، بدون حساسیت به حروف بزرگ/کوچک.__contains: شامل متن مورد نظر باشه.__icontains: شامل متن مورد نظر باشه، بدون حساسیت به حروف بزرگ/کوچک.__in: در یک لیست مشخص باشه.__gt: بزرگتر از (greater than).__gte: بزرگتر یا مساوی با.__lt: کوچکتر از (less than).__lte: کوچکتر یا مساوی با.__startswith: با متن مورد نظر شروع بشه.__endswith: با متن مورد نظر تموم بشه.__year,__month,__day: برای فیلتر کردن بر اساس بخشهای مختلف تاریخ.
زنجیر کردن فیلترها، حذف کردن و مرتبسازی
منطق جنگو خیلی انعطافپذیره. شما میتونید متدهای مختلف QuerySet رو مثل زنجیر به هم وصل کنید.
پرامپت پیشنهادی: «یه QuerySet جنگو برام بنویس که تمام پستهای منتشر شده در سال ۲۰۲۴ رو پیدا کنه، به جز اونایی که عنوانشون با 'چرا' شروع میشه، و در نهایت نتایج رو بر اساس عنوان و به ترتیب حروف الفبا مرتب کنه.»
Post.objects.filter(publish__year=2024).exclude(title__startswith='چرا').order_by('title')
- زنجیر کردن (Chaining): میتونید چندتا `filter` رو پشت سر هم بیارید.
- حذف کردن (Exclude): با متد `exclude` میتونید نتایجی که نمیخواید رو حذف کنید.
- مرتبسازی (Order By): با متد `order_by` میتونید نتایج رو مرتب کنید. (علامت منفی `-` برای ترتیب نزولی).
محدود کردن، شمردن و حذف کردن نتایج
گاهی وقتا فقط به چند نتیجه اول نیاز داریم، یا میخوایم تعداد کل نتایج رو بدونیم، یا یه آبجکت رو کاملاً حذف کنیم.
پرامپت پیشنهادی: «کدهای لازم برای کارهای زیر رو با QuerySet جنگو بهم بده: 1. ۵ پست آخر رو بهم نشون بده. 2. تعداد کل پستهای منتشر شده رو بهم بگو. 3. پستی با شناسه (id) شماره ۱ رو از دیتابیس حذف کن.»
# 1. محدود کردن نتایج (مثل LIMIT در SQL)
latest_posts = Post.objects.all()[:5]
# 2. شمردن نتایج (مثل COUNT در SQL)
total_posts = Post.objects.filter(status=Post.Status.PUBLISHED).count()
# 3. حذف کردن آبجکت
post_to_delete = Post.objects.get(id=1)
post_to_delete.delete()
همونطور که میبینید، با درک منطق کلی QuerySetها و کمک گرفتن از هوش مصنوعی برای جزئیات، میتونید تقریباً هر کاری با دیتابیس انجام بدید!
جستجوهای پیچیده با آبجکتهای Q
تا الان هر چی فیلتر نوشتیم، با عملگر منطقی AND (و) ترکیب میشدن. یعنی وقتی میگفتیم `filter(author='admin', status='PB')`، دنبال پستهایی میگشتیم که نویسندهشون «و» وضعیتشون یکی باشه. اما اگه بخوایم از عملگر OR (یا) استفاده کنیم چی؟
منطق جنگو برای این کار، استفاده از آبجکتهای Q هست. شما میتونید هر شرط فیلتر رو داخل یه آبجکت Q بذارید و بعد با عملگرهای `|` (برای OR) و `&` (برای AND) اونها رو با هم ترکیب کنید.
پرامپت پیشنهادی: «یه QuerySet جنگو با استفاده از آبجکت Q برام بنویس که تمام پستهایی رو پیدا کنه که عنوانشون یا با کلمه 'جنگو' شروع میشه یا با کلمه 'پایتون'.»
from django.db.models import Q
Post.objects.filter(
Q(title__startswith='جنگو') | Q(title__startswith='پایتون')
)
QuerySetها تنبل هستن! (Lazy Evaluation)
یه نکته خیلی مهم در مورد QuerySetها اینه که تنبل (Lazy) هستن. منطقش چیه؟ تا وقتی که واقعاً به نتایج نیاز نداشته باشید، هیچ کوئریای به دیتابیس زده نمیشه. شما میتونید صدتا فیلتر رو به هم زنجیر کنید، اما تا لحظهای که نخواید نتایج رو ببینید یا ازشون استفاده کنید، جنگو به دیتابیس زحمت نمیده. این باعث میشه QuerySetها خیلی بهینه و کارآمد باشن.
۱۲. ساخت مدیرهای سفارشی (Custom Managers)
تا الان از مدیر پیشفرض جنگو یعنی objects استفاده میکردیم (مثلاً `Post.objects.all()`). اما گاهی وقتا ما یه فیلتر خاص رو خیلی زیاد تکرار میکنیم. مثلاً تو وبلاگ ما، خیلی پیش میاد که فقط به پستهای «منتشر شده» نیاز داشته باشیم.
منطق مدیر سفارشی اینه که یه میانبر برای کوئریهای پراستفادهمون بسازیم. ما میخوایم یه مدیر به اسم `published` بسازیم که همیشه فقط پستهای منتشر شده رو برگردونه تا به جای کد طولانی، فقط بنویسیم `Post.published.all()`.
پرامپت پیشنهادی: «برای مدل Post من یه مدیر سفارشی به اسم published بساز که فقط پستهایی با وضعیت 'PUBLISHED' رو برگردونه. کد کاملش رو برای فایل models.py بهم بده.»
هوش مصنوعی این کد رو به شما میده که باید به فایل `models.py` اضافه کنید:
# ... بالای کلاس Post ...
class PublishedManager(models.Manager):
def get_queryset(self):
return super().get_queryset().filter(status=Post.Status.PUBLISHED)
class Post(models.Model):
# ... فیلدهای قبلی ...
# اضافه کردن مدیرها به مدل
objects = models.Manager() # مدیر پیشفرض
published = PublishedManager() # مدیر سفارشی ما
# ... کلاس Meta و متد __str__ ...
حالا دیگه هر جا فقط به پستهای منتشر شده نیاز داشتید، میتونید از میانبر `Post.published` استفاده کنید که هم کدتون رو تمیزتر میکنه و هم از تکرار جلوگیری میکنه.
۱۳. ساخت ویوهای لیست و جزئیات پستها
خب، تا اینجا زیرساخت دیتابیسمون رو کامل ساختیم. حالا وقتشه که اطلاعات رو به کاربر نشون بدیم. این کار وظیفه ویوها (Views) است.
منطق ویو در جنگو خیلی ساده است: یه تابع پایتونیه که یه درخواست وب (Request) از کاربر میگیره و یه پاسخ وب (Response) بهش برمیگردونه. تمام منطق برنامه (اینکه چه دادهای از دیتابیس بگیریم و باهاش چیکار کنیم) داخل ویو اتفاق میافته.
در بخش بعدی، اولین ویوهای اپلیکیشن وبلاگمون رو میسازیم، براشون URL تعریف میکنیم و در نهایت با استفاده از تمپلیتها، اونها رو به شکل صفحات وب زیبا به کاربر نمایش میدیم. آماده باشید! 🚀