سلام امیدوارم حالتون خوب باشه. در آموزش Class-based Views در جنگو که اولین قسمت آموزش ویوهای کلاس محور هست میخوایم با CBVs ها آشنا بشیم و تفاوتش با FBVs ها بدونیم.
من انتظار دارم که شما آشنایی مقدماتی با جنگو و صد البته شی گرایی در پایتون داشته باشید که بتونید مفاهیم آموزش Class-based Views در جنگو رو بهتر متوجه بشید. هر چه شی گرایی توی پایتون رو بهتر بدونید، یادگیری جنگو برای شما راحت تر و لذت بخش تر میشه.
اگه داکیومنت های جنگو رو مطالعه کرده باشید بعد از ساختن پروژه و اپلیکیشن، ساختن اولین ویو در جنگو رو آموزش داده و کد زیر رو نوشته (اینجا):
from django.http import HttpResponse
def index(request):
return HttpResponse("Hello, world. You're at the polls index.")
همانطوری که مشخصه ویو در واقع یک فانکشن پایتونی هست که پارامتر ورودی اون request هست. (البته مجبور نیستیم که دقیقا بنویسیم request) و در ادامه این ویو با استفاده از متد HttpResponse یه متن ساده رو نمایش میده. ما فعلا به بدنه ویو کاری نداریم.
ما با استفاده از فانکشن هایی شبیه به این میتونیم یه وب سایت کامل رو پیاده سازی کنیم و اگه از این روش استفاده کنیم اصطلاحا فانکشن بیس کار کردیم. به این ویوها FBVs می گن.
برای اینکه از این ویوها استفاده کنیم باید در فایل urls.py مسیر یا path مناسبش رو بنویسیم. به این شکل:
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='index'),
]
اینجا درون لیست ulr ها یا همون urlpatterns یک فانکشن path اضافه شده که آرگومان اولش مسیر هست و آرگومان دوم همون ویو ماست. آرگومان سوم هم که اختیاری هست و یه نام برای مسیری هست که ساختیم.
حالا فرض کنید میخواهیم یک ویو جدید بسازیم که قراره از دیتابیس لیست همه یوزرهای سایت رو برای ما لود کنه، اسم این ویو رو user_list در نظر می گیریم و کد فانکشن ویو رو با هم می نویسیم:
def user_list(mmm):
users = User.objects.all()
context = {
'users': users
}
return render(mmm, 'app1/user_list.html', context=context)
توی این کد لیست همه کاربران سایت رو گرفتیم و به کانتکس فرستادیم. کد user_list.html رو هم می نویسیم:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>User List</title>
</head>
<body>
{% for user in user_list %}
<h4>{{user.username}}</h4>
{% endfor %}
</body>
</html>
و در نهایت کد urls.py رو به صورت زیر می نویسیم:
from django.urls import path
from . import views
urlpatterns = [
path('user-list/', views.user_list, name='user_list'),
]
اگه قبلا کاربری ذخیره کرده باشیم، لیست کاربرهارو توی خروجی می تونیم بینیم. تا اینجای کار با FBVs پیش رفتیم. حالا می خواهیم با CBVs آشنا بشیم.
در جنگو میتونم به جای استفاده از فانکشن ها برای ساخت ویو، از کلاس ها استفاده کنیم که به این روش CBVs میگن. البته همزمان میشه از هر دو روش استفاده کرد و برنامه نویس مجبور نیست از روش خاصی استفاده کنه.
کد معادل فانکشن ویوی که ساختیم در حالت CBV رو می نویسیم:
class UserList2(generic.ListView):
model = User
اینجا از یه کلاس به اسم ListView ارث بری کردیم . بدنه ویو هم فقط یک دستور داره . مدل رو براش مشخص کردیم. حالا path مربوط به این ویو رو تنظیم می کنیم:
urlpatterns = [
path('user-list/', views.user_list, name='user_list'),
path('user-list2/', views.UserList2.as_view(), name='user_list2'),
]
برای اینکه ویو کلاس محور ما کارشو درست انجام بده بعد از اسم ویو از متد as_view() استفاده می کنیم.
پروژه رو ران میکنیم. انتظار داریم که خطای templatenotfound بده. جنگو دنبال یه فایل به اسم user_list.html میگرده و چندتا مسیر رو جستجو میکنه. و چون این فایل هارو پیدا نکرده خطا میده.
ما فایل user_list.html رو توی فولدر app1 (اسم اپلیکیشن ما) -> فولدر template -> فولدر auth می سازیم. و محتوای html همون کد html حالت فانکشنی می نویسیم.
یه بار دیگه خروچی رو رفرش می کنیم. همه چیز اوکی میشه. فقط با یک خط کد لیست کاربران نمایش داده شد.
چند تا نکته اینجا هست. جنگو اسم تمپلت رو برحسب مدل انتخاب شده تعیین میکنه. اینجا مدل User هست، پس اسم تمپلت user_list میشه و اسم کانتکس هم به همین صورت تنظیم میشه. البته همه این مقادیر قابل شخصی سازی و override هستند.
همونطوری که دیدیم می تونیم به جای استفاده از فانکشن ها از کلاس ها استفاده کنیم. اما URL resolver جنگو وقتی یک رکوئست رو میگیره انتظار داره بر حسب اون path که مشخص کردیم رکوئست و آرگومان هارو به یک فانکشن callable ارسال کنه و نه یک کلاس. اینجاست که متد as_view() وارد عمل میشه.
متد as_view() چطور کار میکنه؟
متد as_view یک classmethod هست. یا اگه بخواهیم دقیق تر بگیم یک classonlymethod هست. میدونید که کلاس متدها توی پایتون cls یا کلاس رو به عنوان یکی از آرگومان های ورودی دریافت می کنند. as_view یک فانکشن بر میگردونه که callable هست و قابل استفاده توسط url resolver هست.
as_view یک نمونه یا instance از کلاس رو میسازه و متد setup رو که کارش initialize کردن attributeهای اون کلاس هست رو کال میکنه و بعد متد dispatch رو صدا میزنه. متد dispatch هم به http method دریافتی نگاه میکنه (مقدارش میتونه get post head یا هر چیز دیگه ای باشه). پس متد مناسب رو ران میکنه و اگه متد مناسب رو نبینه استثنای HttpResponseNotAllowed رو raise می کنه.
حالا معایب و مزایای روش FBVs و CBVs رو مقایسه کنیم:
FBVS:
مزایا: خوانایی بهتر است، پیاده سازی راحت تر است.
معایب : تکرار کدها، استفاده از عبارات شرطی
روش CBVs :
مزایا: قابلیت استفاده مجدد از کد، جلوگیری از تکرارکدها، توسعه راحت تر
معایب: خوانایی سخت تر
همانطوری که در آموزش Class-based Views در جنگو – قسمت اول دیدید در CBVs کدهای کمتری نوشته میشه چون ما از یک سری کدهای از پیش نوشته شده به اسم generic class ها استفاده می کنیم. همه این جنریک کلاس ها از کلاس View ارث بری می کنند.
علاوه بر جنریک کلاس ها، توسعه دهندگان جنگو یک سری Mixin هم ساختن که ما میتونیم از اونها در کنار یک جنریگ کلاس استفاده کنیم. پس برای ساختن یک ویو کلاس بیس می تونیم از یک جنریک کلاس و یک یا چند میکیسن استفاده کنیم.
در قسمت بعد با جنریک کلاس های جنگو آشنا میشیم.