این آموزش پس از گذراندن آموزش قسمت 2 شروع می شود. در این آموزش قرار است وب اپلیکیشن نظرسنجی را ادامه داده و روی ساخت interface های عمومی به نام “views” تمرکز کنیم.
از کجا کمک بگیرم:
اگر در طول این آموزش با مشکل مواجه شدید، لطفا به بخش Getting Help قسمت FAQ مراجعه کنید.
یک view نوعی صفحه وب در برنامه های جنگو است که بطور کلی عملکرد خاصی را ارائه می دهد و دارای یک الگوی خاص است. به عنوان مثال در یک برنامه وبلاگ، ممکن است view های زیر را داشته باشیم:
در برنامه نظر سنجی خود، ما چهار view زیر را داریم:
در جنگو صفحات وب و سایر محتواها، توسط view ها ارائه می شود. هر view با یک تابع پایتون (یا متد، در مورد view های مبتنی بر کلاس) نشان داده می شوند. جنگو با بررسی URL درخواستی (بطور دقیق بخشی از URL بعد از نام دامنه) یک نمای را انتخاب می کند.
حال در زمان خود در وب ممکن است با قشنگی هایی مانند ME2/Sites/dirmod.htm?sid=&type=gen&mod=Core+Pages&gid=A6CD4967199A42D9B65B1B
برخورد کرده باشید.
خوشحال خواهید شد که بدانید جنگو به ما امکان الگو های URL بسیار قشنگ تر از آن را می دهد.
الگوی URL شکل کلی یک URL است - برای مثال: /newsarchive/<year>/<month>/
جنگو برای رسیدن از یک URL به یک view، از آنچه به عنوان view شناخته می شود استفاده می کند. یک URLconf الگوهای URL را به view ها نگاشت می کند.
این آموزش دستور العمل های اولیه استفاده از URLconfs را ارائه می دهد و می توانید برای اطلاعات بیشتر به URL dispatcher مراجعه کنید.
حال بیایید چند view دیگر به polls/views.py
اصافه کنیم. این دیدگاه ها کمی متفاوت هستند، زیرا استدلال می کنند که:
def detail(request, question_id):
return HttpResponse("You're looking at question %s." % question_id)
def results(request, question_id):
response = "You're looking at the results of question %s."
return HttpResponse(response % question_id)
def vote(request, question_id):
return HttpResponse("You're voting on question %s." % question_id)
این view های جدید را به ماژول polls.urls
با فراخوانی متد path()
به یکدیگر متصل کنید:
from django.urls import path
from . import views
urlpatterns = [
# ex: /polls/
path('', views.index, name='index'),
# ex: /polls/5/
path('<int:question_id>/', views.detail, name='detail'),
# ex: /polls/5/results/
path('<int:question_id>/results/', views.results, name='results'),
# ex: /polls/5/vote/
path('<int:question_id>/vote/', views.vote, name='vote'),
]
نگاهی به مرورگر خود در مسیر “/polls/34/” بیندازید.
متد detail()
را اجرا کنید و هر شناسه ای را که در URL قرار می دهید، نمایش بدهید.
برای دسترسی به “/polls/34/results/” و “/polls/34/vote/” تلاش کنید. اینها نتایج جایگاه دار صفحات نظر سنجی و رای گیری را نشان می دهند.
وقتی کسی صفحه ای را از وبسایت شما درخواست می کند، مثلا “/polls/34/” جنگو ماژول mysite.urls
را بارگیری می کند.
زیرا با تنظیم ROOT_URLCONF
به آن اشاره می شود.
متغیری به نام urlpatterns
را پیدا می کند و و الگو را به ترتیب طی می کند
پس از یافتن مورد مطابق، در 'polls/'
متن مطابق با ("polls/"
) را حذف می کند و متن باقیمانده را به ‘polls.urls’ می فرستد.
قسمت URLconf برای پردازش های بیشتر است. در آنجا با '<int:question_id>/'
مطابقت دارد و در نتیجه به نمای detail()
فراخوانی می شود.
مانند مورد زیر:
detail(request=<HttpRequest object>, question_id=34)
قسمت question_id=34
از <int:question_id>
آمده است. استفاده از براکت زاویه دار بخشی از URL را “captures” می کند و آن را به عنوان
آرگومان کلیدی به تابع view ارسال می کند.
قسمت question_id
از رشته، نامی را که برای شناسایی الگوی منطبق استفاده می شود، تعریف می کند.
و قست int
مبدلی است که تعیین می کند چه الگوهایی باید با این قسمت از مسیر URL مطابقت داشته باشند.
علامت (:
) مبدل و نام الگو را از هم جدا می کند.
هر نما مسئول انجام یکی از دو کار است: برگرداندن شی HttpResponse
حاوی محتوای صفحه درخواستی یا
ایجاد استثناهایی مانند Http404
. بقیه موارد به عهده شماست.
نمای شما قادر خواهد بود سوابق را از پایگاه داده بخواند یا نه. می تواند از یک سیستم قالب آماده مانند جنگو – یا سیستم قالب پایتون شخص ثالث – استفاده کند یا نه. می تواند یک فایل PDF تولید کند، XML را خروجی دهد، یک فایل ZIP در پرواز ایجاد کند، هر چیزی که می خواهید در واقع با استفاده از هر کتابخانه پایتون که می خواهید.
تمام چیزی که جنگو نیاز دارد کلاس HttpResponse
است. یا یک استثنا.
از آنجاییکه راحت است، بیاییداز … پایگاه داده خود جنگو استفاده کنیم که در … پوشش دادیم. در اینجا یک ضربه در نمای جدید … وجود دارد که آخرین سوالات نظرسنجی را در سیستم نشان می دهد که با کاما از یکدیگر جدا شده اند، بر اساس تاریخ انتشار:
from django.http import HttpResponse
from .models import Question
def index(request):
latest_question_list = Question.objects.order_by('-pub_date')[:5]
output = ', '.join([q.question_text for q in latest_question_list])
return HttpResponse(output)
# Leave the rest of the views (detail, results, vote) unchanged
با این حال، مشکلی در اینجا وجود دارد: طراحی صفحه در نمای سخت کدگذاری شده است. اگر می خواهید ظاهر صفحه را تغییر دهید، باید این کد پایتون را ویرایش کنید. پس بیایید از سیستم قالب جنگو برای جدا کردن طرح از پایتون با ایجاد قالبی استفاده کنیم که view بتواند از آن استفاده کند.
ابتدا یک دایرکتوری به نام templates
در دایرکتوری polls
خود ایجاد کنید.
جنگو در آنجا به دنبال الگوها می گردد.
تنظیمات TEMPLATES
پروژه شما توضیح می دهد که جنگو چگونه قالب هارا بارگیری و رندر می کند.
فایل تنظیمات پیش فرض بک اند DjangoTemplates
را پیکربندی می کند که گزینه APP_DIRS
روی True
تنظیم شده است.
طبق قرارداد DjangoTemplates
به دنبال یک زیر شاخه “templates” در هر یک از INSTALLED_APPS
می گردد.
در دایرکتوری templates
که به تازگی ایجاد کردید، دایرکتوری دیگری به نام polls
ایجاد کنید و در آن فایلی به نام index.html
ایجاد کنید.
به عبارت دیگر، الگوی شما باید در polls/templates/polls/index.html
باشد.
به دلیل نحوه عملکرد بارگذار الگوی app_directories
همانطور که در بالا توضیح داده شد، می توانید به این الگو در جنگو
به عنوان polls/index.html
مراجعه کنید.
فضای نام قالب
اکنون ممکن است بتوانیم قالب های خود را مستقیما در polls/templates
قرار دهیم
(بجای ایجاد زیر شاخه polls
دیگر)
اما در واقع ایده بدی است. جنگو اولین قالبی را که پیدا می کند، و اگر شما یک الگو با همین نام
در یک برنامه متفاوت داشته باشید، جنگو نمی تواند بین آنها تمایز قائل شود.
اما باید بتوانیم جنگو را به سمت نطقه مناسب هدایت کنیم و بهترین راه برای اطمینان از این امر
استفاده از فضای نام آنها است.
یعنی با قرار دادن آن الگو ها در پوشه ی دیگر که برای خود برنامه نام گذاری شده است.
کد زیر را در آن قالب قرار دهید:
{% if latest_question_list %}
<ul>
{% for question in latest_question_list %}
<li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>
{% endfor %}
</ul>
{% else %}
<p>No polls are available.</p>
{% endif %}
توجه
برای کوتاه کردن آموزش همه ی نمونه های قالب از HTML ناقص استفاده می کنند. در پروژه های خود شما باید از complete HTML documents استفاده کنید.
اکنون بیایید برای استفاده از قالب نمای index
را در polls/views.py
بروزرسانی کنیم:
from django.http import HttpResponse
from django.template import loader
from .models import Question
def index(request):
latest_question_list = Question.objects.order_by('-pub_date')[:5]
template = loader.get_template('polls/index.html')
context = {
'latest_question_list': latest_question_list,
}
return HttpResponse(template.render(context, request))
کدی که قالب را بارگذاری می کند … صدا زدیم که در یک متن پاس داده می شود. متن یک فرهنگ لغت نگاشت قالب نام متغیر ها به اشیاء پایتون است.
صفحه را با نشان دادن مرورگر خود روی … بارگیری کنید. و باید یک bullet لیست حاوی سوال “What’s up” از Tutorial 2 مشاهده کنید. لینک به صفحه جزییات سوال اشاره دارد.
render()
¶این یک اصطلاح بسیار رایج است که یک الگو را بارگیری می کند، یک متن را پر می کند و یک شی … را با نتیجه الگوی ارائه شده برمیگرداند. جنگو یک میانبر ارائه می دهد. در اینجا نمای کامل … است که بازنویسی شده است.
from django.shortcuts import render
from .models import Question
def index(request):
latest_question_list = Question.objects.order_by('-pub_date')[:5]
context = {'latest_question_list': latest_question_list}
return render(request, 'polls/index.html', context)
توجه داشته باشید که وقتی این کار را در همه ی نماها انجام دادیم، دیگر نیازی به وارد کردن loader
و HttpResponse
نداریم.
(شما می خواهید HttpResponse
را نگه دارید اگر هنوز روش های خرد برای detail
و results
و vote
را داشته باشید)
تابع render()
شی درخواست را به عنوان اولین آرگومان، نام الگو را به عنوان دومین آرگومان
و دیکشنری را به عنوان آرگومان سوم اختیاری خود می گیرد.
یک شی HttpResponse
از الگوی ارائه شده با زمینه داده شده را بر میگرداند.
اکنون، بیایید به نمای جزئیات سؤال بپردازیم – صفحه ای که متن سؤال را برای یک نظرسنجی مشخص نشان می دهد. این نما است:
from django.http import Http404
from django.shortcuts import render
from .models import Question
# ...
def detail(request, question_id):
try:
question = Question.objects.get(pk=question_id)
except Question.DoesNotExist:
raise Http404("Question does not exist")
return render(request, 'polls/detail.html', {'question': question})
مفهومی جدید: اگر سوالی با شناسه درخواستی وجود نداشته باشد، نمای استثنا Http404
را ایجاد می کند.
ما کمی بعد در مورد آنچه که می توانید در قالب … قرار دهید بحث خواهیم کرد. اما اگر میخواهید به سرعت مثال بالا کار کند، فایلی حاوی فقط:
{{ question }}
فعلا کار شمارا راه می اندازد.
get_object_or_404()
¶یک اصطلاح بسیار رایج برای استفاده از get()
است.
و اگر شی وجود نداشت Http404
را بالا بیاورد. جنگو یک میانبر ارائه می دهد. در اینجا نمای detail()
است که بازنویسی شده است:
from django.shortcuts import get_object_or_404, render
from .models import Question
# ...
def detail(request, question_id):
question = get_object_or_404(Question, pk=question_id)
return render(request, 'polls/detail.html', {'question': question})
تابع get_object_or_404()
یک مدل جنگو را به عنوان اولین آرگومان خود و تعدادی دلخواه آرگومان کلیدی دریافت می کند.
که به get()
ارسال می کند.
اگر شی وجود نداشته باشد، Http404
را نمایش می دهد.
فلسفه
چرا از یک تابع کمکی get_object_or_404()
استفاده می کنیم بجای اینکه بطور خودکار
استثناهای ObjectDoesNotExist
را در سطح بالاتر دریافت کنیم،
یا API مدل Http404
را افزایش دهیم بجای ObjectDoesNotExist
.
زیرا این لایه مدل را به لایه view متصل می کند.
یکی از مهمترین اهداف طراحی جنگو حفظ loose coupling است.
برخی از coupling های کنترل شده در ماژول django.shortcuts
معرفی شده است.
همچنین یک تابع get_list_or_404()
نیز وجود دارد که دقیقا مانند get_object_or_404()
کار می کند – بجز استفاده از filter()
بجای get()
.
اگر لیست خالی باشد، خطای … را بالا می آورد.
بازگشت به نمای detail()
برای برنامه نظرسنجی ما، با توجه به متغیر زمینه question
در اینجا
الگوی polls/detail.html
ممکن است شبیه باشد:
<h1>{{ question.question_text }}</h1>
<ul>
{% for choice in question.choice_set.all %}
<li>{{ choice.choice_text }}</li>
{% endfor %}
</ul>
سیستم قالب از نحوه ی جستجوی نقطه برای دسترسی به ویژگی های متغیر استفاده می کند.
در مثال {{ question.question_text }}
ابتدا جنگو جستجوی فرهنگ لغت را روی شی question
انجام می دهد.
در صورت عدم موفقیت، جستجوی ویژگی را امتحان می کند – که در این مورد کار می کند.
اگر جستجوی ویژگی ناموفق بود، جستجوی فهرست به فهرست را امتحان می کند.
فراخوانی متد در حلقه {% for %}
انجام می شود:
question.choice_set.all
به عنوان کد پایتون question.choice_set.all()
تفسیر می شود،
که تکرار پذیری از اشیاء Choice
را بر می گرداند و برای استفاده در تگ {% for %}
مناسب است.
برای اطلاعات بیشتر در مورد الگوها به template guide راهنمای قالب مراجعه کنید.
به یاد داشته باشید، زمانی که ما لینک یک سوال را در قالب polls/index.html
نوشتیم، پیوند تا حدی به این صورت هاردکد شده است:
<li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>
مشکل این رویکرد هاردکد این است که تغییر URL ها در پروژه هایی با قالب های
زیاد چالش بر انگیز می شود. با این حال، از آنجاییکه شما آرگومان نام را در توابع path()
در
ماژول polls.urls
تعریف کردید، می توانید با استفاده از تگ {% url %}
الگو آن را پیکر بندی کنید:
<li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>
روش کار این است که به دنبال تعریف URL همانطور که در ماژول polls.urls
مشخص شده است بگردید.
شما می توانید دقیقا جایی که نام URL در ‘detail’ زیر تعریف شده است:
...
# the 'name' value as called by the {% url %} template tag
path('<int:question_id>/', views.detail, name='detail'),
...
اگر می خواهید نمای جزییات نظرسنجی URL را تغییر دهید، شاید
به چیزی مانند polls/specifics/12/
بجای انجام آن در الگو (یا الگوها) آن را در polls/urls.py
تغییر دهید:
...
# added the word 'specifics'
path('specifics/<int:question_id>/', views.detail, name='detail'),
...
پروژه آموزشی فقط یک برنامه دارد، polls
. در پروژه های واقعی جنگو، ممکن است پنج، ده، بیست برنامه یا بیشتر وجود داشته باشد. جنگو چگونه نام URL ها را بین آنها متمایز می کند؟ برای مثال، برنامه polls
دارای نمای detail
است، و همچنین ممکن است یک برنامه در همان پروژه که برای یک وبلاگ است. چگونه می توان آن را طوری ساخت که جنگو بداند هنگام استفاده از تگ الگوی {% url %}
کدام نمای برنامه را برای یک URL ایجاد کند؟
پاسخ این است که فضاهای نام را به URLconf خود اضافه کنید.
در فایل polls/urls.py
پیش بروید و یک app_name
اضافه کنید تا فضای نام برنامه را تنظیم کنید:
from django.urls import path
from . import views
app_name = 'polls'
urlpatterns = [
path('', views.index, name='index'),
path('<int:question_id>/', views.detail, name='detail'),
path('<int:question_id>/results/', views.results, name='results'),
path('<int:question_id>/vote/', views.vote, name='vote'),
]
اکنون الگوی polls/index.html
خود را از قسمت زیر تغییر دهید:
<li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>
برای اشاره به نمای جزییات فضای نام داریم:
<li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li>
وقتی به نوشتن نماها تسلط پیدا کردید، قسمت چهارم این آموزش را بخوانید تا اصول اولیه پردازش فرم و نماهای عمومی را بیاموزید.
Jul 27, 2022