
اکنون که نحوه استفاده از ORM را یاد گرفتهاید، آماده هستید تا Viewهای برنامه وبلاگ را ایجاد کنید.
در جنگو، View تنها یک تابع پایتون است که یک درخواست وب (Web Request) را دریافت کرده و یک پاسخ وب (Web Response) را برمیگرداند. تمام منطق لازم برای تولید پاسخ موردنظر در داخل View قرار میگیرد.
ابتدا Viewهای برنامه را ایجاد میکنید، سپس برای هر View یک الگوی URL تعریف میکنید و در نهایت قالبهای HTML را برای نمایش دادههای تولیدشده توسط Viewها میسازید. هر View یک Template را رندر کرده، متغیرهای لازم را به آن ارسال میکند و در نهایت یک پاسخ HTTP شامل خروجی رندرشده را برمیگرداند.
ابتدا یک View برای نمایش فهرست پستها ایجاد میکنیم.
فایل views.py مربوط به برنامه blog را ویرایش کنید تا به شکل زیر درآید:
from django.shortcuts import render from .models import Post def post_list(request): posts = Post.published.all() return render( request, 'blog/post/list.html', {'posts': posts} )
این اولین View ما در جنگو است.
تابع post_list تنها یک پارامتر به نام request دریافت میکند. این پارامتر برای تمام Viewهای جنگو الزامی است.
در این View، تمام پستهایی که وضعیت PUBLISHED دارند را با استفاده از Manager سفارشی published که قبلاً ایجاد کردیم، بازیابی میکنیم.
در پایان، از میانبر (shortcut) تابع ()render که توسط جنگو فراهم شده است استفاده میکنیم تا فهرست پستها را با Template مشخصشده رندر کنیم.
تابع ()render سه آرگومان اصلی دریافت میکند:
شیء request
مسیر Template
متغیرهای Context که باید به Template ارسال شوند.
این تابع یک شیء HttpResponse شامل متن رندرشده (که معمولاً کد HTML است) برمیگرداند.
میانبر ()render همچنین Request Context را نیز در نظر میگیرد؛ بنابراین هر متغیری که توسط Template Context Processorها تنظیم شده باشد، در Template قابل دسترسی خواهد بود.
Context Processorها تنها توابعی هستند که متغیرهایی را به Context قالب اضافه میکنند. در فصل چهارم (Building a Social Website) با نحوه استفاده از آنها آشنا خواهید شد.
اکنون یک View دیگر برای نمایش یک پست منفرد ایجاد میکنیم.
تابع زیر را به فایل views.py اضافه کنید:
from django.http import Http404 def post_detail(request, id): try: post = Post.published.get(id=id) except Post.DoesNotExist: raise Http404("No Post found.") return render( request, 'blog/post/detail.html', {'post': post} )
این View با نام post_detail شناخته میشود.
این View شناسه (id) یک پست را به عنوان آرگومان دریافت میکند.
در داخل View تلاش میکنیم با فراخوانی متد ()get. روی Manager published، شیء Post مربوط به آن شناسه را بازیابی کنیم.
اگر هیچ نتیجهای پیدا نشود، استثنای Post.DoesNotExist رخ میدهد که در این حالت یک استثنای Http404 ایجاد میکنیم تا پاسخ HTTP 404 (Not Found) به کاربر برگردانده شود.
در پایان نیز با استفاده از تابع ()render پست بازیابیشده را توسط Template مربوطه نمایش میدهیم.
get_object_or_404جنگو میانبری در اختیار ما قرار میدهد که متد ()get. را روی یک Model Manager اجرا کرده و در صورت پیدا نشدن شیء، بهجای ایجاد استثنای DoesNotExist، مستقیماً استثنای Http404 را ایجاد میکند.
فایل views.py را ویرایش کرده، get_object_or_404 را وارد (import) کنید و View post_detail را به شکل زیر تغییر دهید:
from django.shortcuts import get_object_or_404, render # ... def post_detail(request, id): post = get_object_or_404( Post, id=id, status=Post.Status.PUBLISHED ) return render( request, 'blog/post/detail.html', {'post': post} )
اکنون در View جزئیات، از میانبر ()get_object_or_404 برای بازیابی پست موردنظر استفاده میکنیم.
این تابع شیئی را که با پارامترهای دادهشده مطابقت دارد بازیابی میکند و اگر هیچ شیئی یافت نشود، یک خطای HTTP 404 (Not Found) ایجاد میکند.
الگوهای URL امکان نگاشت (Mapping) آدرسهای اینترنتی به Viewها را فراهم میکنند.
هر الگوی URL از سه بخش تشکیل شده است:
یک الگوی رشتهای (Pattern)
یک View
و در صورت نیاز، یک نام (Name) که امکان ارجاع به URL را در کل پروژه فراهم میکند.
جنگو الگوهای URL را به ترتیب بررسی میکند و به محض اینکه اولین الگوی منطبق با URL درخواستشده را پیدا کرد، جستجو متوقف میشود.
سپس View مربوط به آن الگو را بارگذاری کرده و آن را اجرا میکند. هنگام اجرای View، یک نمونه از کلاس HttpRequest و همچنین آرگومانهای موقعیتی یا کلیدواژهای استخراجشده از URL به آن ارسال میشوند.
در پوشه برنامه blog فایلی با نام urls.py ایجاد کرده و کد زیر را در آن قرار دهید:
from django.urls import path from . import views app_name = 'blog' urlpatterns = [ # post views path('', views.post_list, name='post_list'), path('<int:id>/', views.post_detail, name='post_detail'), ]
در این کد، با استفاده از متغیر app_name یک فضای نام (Application Namespace) برای برنامه تعریف میکنید.
این کار باعث میشود URLهای هر برنامه بهصورت سازمانیافته مدیریت شوند و هنگام ارجاع به آنها از نام برنامه استفاده کنید.
در اینجا با استفاده از تابع path() دو الگوی URL تعریف شده است.
الگوی اول هیچ آرگومانی دریافت نمیکند و به View post_list متصل شده است.
الگوی دوم به View post_detail متصل است و یک آرگومان به نام id دریافت میکند که باید یک عدد صحیح باشد. این تبدیل توسط Path Converter از نوع int انجام میشود.
برای استخراج مقادیر از URL از علامتهای < > استفاده میشود.
هر مقداری که به صورت <parameter> تعریف شود، بهصورت پیشفرض به شکل رشته (String) دریافت خواهد شد.
برای محدود کردن نوع داده، از Path Converterها استفاده میکنیم؛ مانند:
<int:year>
که فقط اعداد صحیح را قبول کرده و مقدار را به صورت int به View ارسال میکند.
به عنوان مثال:
<slug:post>
فقط مقادیری را میپذیرد که یک Slug معتبر باشند؛ یعنی رشتهای شامل:
حروف
اعداد
زیرخط (_)
خط تیره (-)
فهرست کامل Path Converterهای موجود در جنگو را میتوانید در مستندات مشاهده کنید:
https://docs.djangoproject.com/en/5.0/topics/http/urls/#path-converters
اگر path() و Path Converterها پاسخگوی نیاز شما نباشند، میتوانید از re_path() استفاده کنید تا الگوهای URL پیچیدهتری را با استفاده از Regular Regex) تعریف نمایید.
اطلاعات بیشتر در:
https://docs.djangoproject.com/en/5.0/ref/urls/#django.urls.re_path
اگر تاکنون با Regular Expression کار نکردهاید، بهتر است ابتدا راهنمای زیر را مطالعه کنید:
https://docs.python.org/3/howto/regex.html
ایجاد یک فایل urls.py مجزا برای هر برنامه، بهترین روش برای قابل استفاده مجدد (Reusable) کردن برنامهها در پروژههای دیگر است.
اکنون باید URLهای برنامه blog را در فایل URL اصلی پروژه وارد (Include) کنیم.
فایل urls.py موجود در پوشه mysite را به شکل زیر تغییر دهید (کد جدید با Bold مشخص شده است):
from django.contrib import admin from django.urls import include, path urlpatterns = [ path('admin/', admin.site.urls), path('blog/', include('blog.urls', namespace='blog')), ]
الگوی URL جدیدی که با استفاده از include() تعریف شده است، تمام URLهای تعریفشده در فایل blog.urls را در مسیر /blog قرار میدهد.
همچنین این URLها تحت فضای نام (Namespace) blog ثبت میشوند.
هر Namespace باید در کل پروژه منحصربهفرد باشد.
از این پس میتوانید بهراحتی با استفاده از Namespace و نام URL به این مسیرها ارجاع دهید، مانند:
blog:post_list
blog:post_detail
برای مطالعه بیشتر درباره Namespaceها به مستندات جنگو مراجعه کنید:
https://docs.djangoproject.com/en/5.0/topics/http/urls/#url-namespaces
اکنون Viewها و الگوهای URL مربوط به برنامه وبلاگ را ایجاد کردهایم.
الگوهای URL، آدرسها را به Viewها نگاشت (Map) میکنند و Viewها مشخص میکنند چه دادهای باید به کاربر بازگردانده شود.
Templateها نحوه نمایش این دادهها را تعیین میکنند. معمولاً Templateها با استفاده از HTML و زبان قالب (Template Language) جنگو نوشته میشوند.
اطلاعات بیشتر درباره زبان قالب جنگو را میتوانید در مستندات زیر مشاهده کنید:
https://docs.djangoproject.com/en/5.0/ref/templates/language/
اکنون Templateهایی را به برنامه اضافه میکنیم تا پستها به شکلی مناسب و کاربرپسند نمایش داده شوند.
در پوشه برنامه blog، ساختار زیر را ایجاد کنید:
templates/ blog/ base.html post/ list.html detail.html
این ساختار فایلهای Template برنامه را تشکیل میدهد.
فایل base.html ساختار اصلی HTML وبسایت را در خود نگه میدارد و صفحه را به دو بخش تقسیم میکند:
محتوای اصلی (Main Content)
نوار کناری (Sidebar)
فایلهای list.html و detail.html از base.html ارثبری میکنند تا بهترتیب View فهرست پستها و View جزئیات یک پست را نمایش دهند.
جنگو دارای یک زبان قالب قدرتمند است که مشخص میکند دادهها چگونه نمایش داده شوند.
این زبان بر سه مفهوم اصلی استوار است:
۱. Template Tag
Template Tagها کنترل میکنند که Template چگونه رندر شود.
{% tag %}
۲. Template Variable
متغیرهای Template هنگام رندر شدن با مقدار واقعی خود جایگزین میشوند.
{{ variable }}
۳. Template Filter
Filterها امکان تغییر یا قالببندی مقدار متغیرها را قبل از نمایش فراهم میکنند.
{{ variable|filter }}
تمام Tagها و Filterهای داخلی جنگو در مستندات زیر موجود هستند:
https://docs.djangoproject.com/en/5.0/ref/templates/builtins/
فایل base.html را ویرایش کرده و کد زیر را در آن قرار دهید:
{% load static %} <!DOCTYPE html> <html> <head> <title>{% block title %}{% endblock %}</title> <link href="{% static "css/blog.css" %}" rel="stylesheet"> </head> <body> <div id="content"> {% block content %} {% endblock %} </div> <div id="sidebar"> <h2>My blog</h2> <p>This is my blog.</p> </div> </body> </html>
{% load static %}
عبارت بالا به جنگو اعلام میکند که Template Tagهای مربوط به فایلهای Static را که توسط برنامه django.contrib.staticfiles ارائه شدهاند بارگذاری کند.
این برنامه در تنظیمات INSTALLED_APPS قرار دارد.
پس از بارگذاری، میتوانید در سراسر Template از Tag زیر استفاده کنید:
{% static %}
این Tag برای درج فایلهای استاتیک مانند:
فایلهای CSS
تصاویر
فایلهای JavaScript
به کار میرود.
در این مثال از آن برای بارگذاری فایل زیر استفاده شده است:
css/blog.css
این فایل در پوشه static/ برنامه قرار دارد.
برای اعمال استایلها، پوشه static/ موجود در کدهای همراه کتاب را در محل مناسب پروژه خود کپی کنید.
محتویات آن در این آدرس قرار دارد:
https://github.com/PacktPublishing/Django-5-by-example/tree/master/Chapter01/mysite/blog/static
در این Template دو Tag از نوع block مشاهده میکنید:
{% block title %}
و
{% block content %}
این Tagها به جنگو اعلام میکنند که این قسمتها در Templateهای فرزند قابل جایگزینی هستند.
بنابراین هر Template که از base.html ارثبری کند، میتواند محتوای این دو بخش را تغییر دهد.
فایل post/list.html را به شکل زیر ویرایش کنید:
{% extends "blog/base.html" %} {% block title %} My Blog {% endblock %} {% block content %} <h1>My Blog</h1> {% for post in posts %} <h2> <a href="{% url 'blog:post_detail' post.id %}"> {{ post.title }} </a> </h2> <p class="date"> Published {{ post.publish }} by {{ post.author }} </p> {{ post.body|truncatewords:30|linebreaks }} {% endfor %} {% endblock %}
با استفاده از Tag زیر:
{% extends "blog/base.html" %}
به جنگو اعلام میکنیم که این Template از blog/base.html ارثبری میکند.
سپس Blockهای title و content را با محتوای موردنظر پر میکنیم.
در داخل Block محتوا، روی مجموعه posts حلقه میزنیم و برای هر پست موارد زیر را نمایش میدهیم:
عنوان
تاریخ انتشار
نویسنده
متن پست
همچنین عنوان هر پست به صفحه جزئیات همان پست لینک شده است.
urlبرای ساخت لینک از Template Tag زیر استفاده شده است:
{% url 'blog:post_detail' post.id %}
این Tag بهصورت پویا (Dynamic) URLها را بر اساس نام آنها تولید میکند.
در اینجا:
blog نام Namespace برنامه است.
post_detail نام URL تعریفشده در فایل urls.py است.
post.id نیز پارامتر لازم برای ساخت URL را فراهم میکند.
همیشه برای ساخت URL در Templateها از Tag زیر استفاده کنید:
{% url %}
و هرگز آدرسها را بهصورت ثابت (Hardcoded) ننویسید.
این کار باعث میشود در آینده اگر ساختار URLها تغییر کرد، نیازی به تغییر Templateها نداشته باشید و نگهداری پروژه بسیار آسانتر شود.
در بدنه پست از دو Filter استفاده شده است:
{{ post.body|truncatewords:30|linebreaks }}
Filter اول: truncatewords
این Filter متن را به تعداد مشخصی از کلمات محدود میکند.
در اینجا:
truncatewords:30
تنها ۳۰ کلمه اول متن نمایش داده میشود.
Filter دوم: linebreaks
این Filter کاراکترهای شکست خط (n\) را به تگهای HTML مناسب مانند <p> و <br> تبدیل میکند تا متن در مرورگر بهدرستی نمایش داده شود.
به یاد داشته باشید:
میتوانید هر تعداد Filter که نیاز دارید پشت سر هم قرار دهید.
خروجی هر Filter، ورودی Filter بعدی خواهد بود.
اکنون وضعیت (Status) اولین پست را به منتشر شده | Published تغییر دهید (مطابق شکل زیر):

سپس چند پست جدید نیز با وضعیت Published ایجاد کنید تا در صفحه فهرست وبلاگ نمایش داده شوند.
ترمینال (Shell) را باز کرده و دستور زیر را برای راهاندازی سرور محیط توسعه اجرا کنید:
python manage.py runserver
سپس در مرورگر خود آدرس زیر را باز کنید:
http://127.0.0.1:8000/blog/
اکنون باید برنامه در حال اجرا باشد و صفحه وبلاگ بهدرستی نمایش داده شود.
خروجی صفحه باید مشابه تصویر زیر باشد.

در مرحله بعد، فایل post/detail.html را به شکل زیر ویرایش کنید:
{% extends "blog/base.html" %} {% block title %} {{ post.title }} {% endblock %} {% block content %} <h1>{{ post.title }}</h1> <p class="date"> Published {{ post.publish }} by {{ post.author }} </p> {{ post.body|linebreaks }} {% endblock %}
در این Template نیز مانند Template قبلی، از فایل blog/base.html ارثبری میکنیم.
سپس مقدار Block title را برابر با عنوان پست (post.title) قرار میدهیم تا عنوان صفحه مرورگر نیز همان عنوان پست باشد.
در Block Content نیز اطلاعات پست نمایش داده میشود که شامل موارد زیر است:
عنوان پست
تاریخ انتشار
نویسنده
متن کامل پست
برای نمایش متن پست از Filter زیر استفاده شده است:
{{ post.body|linebreaks }}
Filter linebreaks کاراکترهای شکست خط (n\) را به تگهای مناسب HTML مانند <p> و <br> تبدیل میکند تا متن با قالببندی صحیح در مرورگر نمایش داده شود.

به URL صفحه نیز دقت کنید؛ این آدرس باید شامل شناسه (ID) خودکار پست باشد، مانند:
/blog/1/
در این مثال، عدد 1 شناسه (Primary Key) پستی است که در حال مشاهده آن هستید. اگر روی پست دیگری کلیک کنید، این عدد به شناسه همان پست تغییر خواهد کرد؛ برای مثال:
/blog/2/
یا:
/blog/5/
این رفتار به این دلیل است که در فایل urls.py الگوی زیر را تعریف کردهایم:
path('<int:id>/', views.post_detail, name='post_detail')
در این الگو، بخش <int:id> مقدار عددی موجود در URL را استخراج کرده و آن را بهصورت آرگومان id به تابع post_detail ارسال میکند. سپس View با استفاده از این شناسه، پست مربوطه را از پایگاه داده بازیابی کرده و نمایش میدهد.
پست قبلی: (۱.۱۴: تنظیم url صفحات و ایجاد صفحه نمایش پست های وبلاگ)
پست بعدی: (۱.۱۵: یادگیری چرخه عمر Request/Response در جنگو)