تفاوت String، StringBuilder و StringBuffer در جاوا
اگر در جاوا یک پیام کوتاه میسازید، عملگر جمع معمولاً خواناترین انتخاب است. اما وقتی هزاران قطعه را در حلقه …
مرورگر یک نشانی درخواست میکند؛ جنگو باید بداند کدام کد را اجرا کند و چه پاسخی برگرداند. ویو در جنگو همین نقطه اتصال درخواست به رفتار برنامه است و پیکربندی مسیرها، درخواست را به آن میرساند. اگر تازه با جنگو کار میکنید، تفاوت ویوی تابعی و کلاسی ممکن است بزرگتر از واقعیت به نظر برسد. در این راهنما، یک مثال بدون پایگاه داده را از مسیر تا قالب میسازیم و بعد میبینیم چه زمانی استفاده از ویوهای عمومی منطقی است.
آخرین بهروزرسانی: ۱۶ آبان ۱۴۰۵ — منابع بررسیشده در این روز: صفحه دریافت جنگو با نسخه پایدار ۶٫۱٫۳، مستندات شاخه ۶٫۱ درباره ویو، مسیر، ویوهای کلاسی و بخش سوم آموزش رسمی؛ مرجع تکمیلی سیسیبیوی.
⚡ پاسخ کوتاه
ویوی تابعی یک تابع دریافتکننده درخواست و بازگرداننده پاسخ است. ویوی کلاسی همین رفتار را در متدهای یک کلاس سازمان میدهد و با as_view به مسیر متصل میشود. path برای مسیرهای معمول، include برای تقسیم مسیرها و render برای ساخت پاسخ از قالب کاربرد دارند. برای شروع و منطق خاص، تابع اغلب شفاف است؛ برای الگوهای تکراری، ویوی عمومی میتواند کد را کمتر کند.
📑 فهرست مطالب
ویو مسئول هماهنگ کردن پاسخ به درخواست است؛ ممکن است داده بخواند، مجوز را بررسی کند و قالبی را به پاسخ تبدیل کند. پاسخ هم الزاماً صفحه اچتیامال نیست: میتواند داده ساختیافته، تغییر مسیر یا خطا باشد. برای توضیح معماری، ساختار مدل، ویو و قالب در جنگو را ببینید؛ این مقاله تمرکزش بر اتصال مسیر و پیادهسازی رفتار است.
در بررسی ۱۶ آبان ۱۴۰۵، صفحه رسمی دریافت جنگو نسخه پایدار ۶٫۱٫۳ را معرفی میکرد و نمونههای این مطلب با مستندات شاخه ۶٫۱ نوشته شدهاند. پروژه قدیمی را صرفاً با کپی کردن شماره نسخه ارتقا ندهید؛ وابستگیها، پشتیبانی نسخه و یادداشت انتشار را بررسی کنید. مفهومهای اصلی این آموزش قدیمیترند، اما همیشه مستندات متناسب با نسخه پروژه خودتان را بخوانید.
اگر هنوز اپلیکیشن ندارید، ابتدا ساخت اپلیکیشن در جنگو را دنبال کنید. در ادامه فرض میکنیم پروژه ساخته شده و اپی به نام pages در فهرست اپهای نصبشده قرار دارد. برای روشن ماندن مسیر درخواست، مثال اولیه پایگاه داده ندارد و از یک فهرست ثابت آموزشی استفاده میکند؛ آن را کاتالوگ واقعی یا معماری نهایی فروشگاه تلقی نکنید.

سادهترین ویو یک تابع پایتون است که درخواست را میگیرد و یک شیء پاسخ برمیگرداند. نام آرگومان معمولاً request است، اما آنچه مهم است قرارداد فراخوانی جنگوست. اگر مسیری پارامتر بگیرد، مقدار آن هم به تابع فرستاده میشود. برگرداندن یک رشته خام یا فراموش کردن بازگشت در یکی از شاخهها، قرارداد ویو را نقض میکند.
# pages/views.py
from django.http import HttpResponse
from django.views.decorators.http import require_GET
@require_GET
def hello(request, name):
return HttpResponse("Hello")
این ویو عمداً مقدار نام را وارد پاسخ نمیکند تا بحث قالب را جدا ببینیم. اگر داده کاربر را مستقیم در رشته اچتیامال قرار میدهید، خطر تزریق محتوا را ارزیابی کنید؛ در مثالهای بعدی از قالب با گریز خودکار استفاده میکنیم. محدود کردن متد به دریافت برای صفحه خواندنی مناسب است، اما مجوز دسترسی یا حفاظت داده را بهخودیخود حل نمیکند.
منطق هماهنگسازی درخواست، مانند خواندن پارامتر، فراخوانی خدمت و انتخاب پاسخ، در ویو جا دارد. محاسبه پیچیده کسبوکار یا اتصال بلندمدت به سرویس بیرونی را بهتر است در لایه مناسب جدا کنید. تابع کوتاهتر راحتتر آزمایش میشود، اما کوتاهی صرف هم هدف نیست؛ مهم آن است که مسئولیتها و مسیر خطا روشن باشند.
اگر رفتار تابع برای دریافت و ارسال فرق دارد، هر شاخه باید اعتبارسنجی و پاسخ مشخص داشته باشد. برای فرم واقعی از امکانات فرم و حفاظت درخواست استفاده کنید؛ داده ارسالشده را معتبر فرض نکنید. در درخواست دریافت، عملیات تغییردهنده وضعیت مانند حذف یا تأیید سفارش انجام ندهید؛ درخواست یک صفحه باید بیخطر و قابل تکرار باشد.
در ویوی کلاسی، رفتار متدهای درخواست را در متدهای کلاس قرار میدهید. کلاس پایه View میتواند درخواست را به get یا post هدایت کند. در تنظیم مسیر، خود کلاس را بدون تبدیل نمیگذاریم؛ as_view یک فراخوانپذیر مناسب برای سامانه مسیر میسازد. این تبدیل بخشی از اتصال کلاس به چرخه درخواست جنگوست، نه یک تزئین اختیاری.
# pages/views.py
from django.http import HttpResponse
from django.views import View
class HelloView(View):
def get(self, request, name):
return HttpResponse("Hello")
این کلاس نسبت به تابع ساده، مزیت جادویی ندارد. وقتی چند روش مرتبط، قابلیت استفاده دوباره یا الگوی مشترک دارید، سازماندهی کلاس میتواند مفید شود. در مقابل، اگر برای فهم یک صفحه لازم است چند فایل و زنجیره وراثت طولانی را بخوانید، سادگی اولیه از دست رفته است. انتخاب را بر اساس نیاز تیم و پیچیدگی واقعی انجام دهید.
جنگو برای الگوهای رایج، ویوهای عمومی دارد. برای نمایش قالبی ساده میتوان از TemplateView استفاده کرد؛ برای فهرست و جزئیات مدل هم کلاسهای مربوط وجود دارند. در این مثال فقط داده نمایشی ثابت میفرستیم تا بدون مهاجرت پایگاه داده قابل فهم باشد. آشنایی با مدلها در جنگو مقدمه گسترش مثال به داده واقعی است.
# pages/views.py
from django.views.generic import TemplateView
class CatalogView(TemplateView):
template_name = "pages/catalog.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["title"] = "Catalog"
context["items"] = ["Book", "Notebook"]
return context
فراخوانی پیادهسازی والد را بیدلیل حذف نکنید؛ ممکن است داده و رفتار لازم را نگه دارد. داده وابسته به درخواست را در جای مناسب برای همان درخواست بسازید، نه در یک ظرف تغییرپذیر مشترک در سطح کلاس. اینکه برای هر درخواست نمونه ویو ساخته میشود، به معنی امن بودن هر شیء مشترکی که به کلاس وصل کردهاید نیست.

جنگو الگوها را بهترتیب بررسی میکند و اولین تطبیق را انتخاب میکند. پس مسیر کلی را پیش از استثناهای خاص نگذارید، مگر این ترتیب را عمداً میخواهید. مسیرها را بدون دامنه و بدون اسلش ابتدای رشته تعریف میکنیم. پارامترهای پرسوجو مثل شماره صفحه جزو تطبیق مسیر نیستند و از بخش مربوط در درخواست خوانده میشوند.
# project/urls.py
from django.urls import include, path
urlpatterns = [
path("pages/", include("pages.urls")),
]
# pages/urls.py
from django.urls import path
from . import views
app_name = "pages"
urlpatterns = [
path("hello/<str:name>/", views.hello, name="hello"),
path("class-hello/<str:name>/", views.HelloView.as_view(), name="class-hello"),
path("catalog/", views.CatalogView.as_view(), name="catalog"),
path("function-catalog/", views.catalog, name="function-catalog"),
]
در فایل دوم به تابع catalog هم ارجاع دادهایم که در بخش بعد تعریف میشود؛ پیش از اجرای پروژه هر دو بخش را کامل کنید. include پیشوند تطبیقیافته را جدا میکند و ادامه مسیر را به تنظیمات اپ میدهد. در نتیجه نشانی فهرست کلاسی در این نمونه زیر پیشوند pages است، نه مستقیم در ریشه سایت. این تفکیک، جابهجایی اپ را سادهتر میکند.
برای مسیرهای عادی از path و مبدلهایی مثل int و slug استفاده کنید. مبدل عدد صحیح، مقدار تطبیقیافته را به عدد تبدیل میکند؛ اما مثبت بودن شناسه، وجود رکورد یا مجاز بودن کاربر را اثبات نمیکند. در re_path از عبارت منظم استفاده میشود و گروههای گرفتهشده معمولاً رشتهاند. وقتی قواعد پیچیده ندارید، عبارت منظم پیچیده فقط هزینه نگهداری اضافه میکند.
مبدل slug پیشفرض برای حروف و ارقام اَسکی، خط تیره و زیرخط است؛ آن را پشتیبانی خودکار از هر نامک فارسی فرض نکنید. برای نیاز متفاوت، قرارداد مسیر را متناسب طراحی کنید. اسلش پایان را هم یکدست نگه دارید و برای درخواستهای تغییردهنده وضعیت به تغییر مسیر خودکار تکیه نکنید؛ خطای مسیر باید پیش از انتشار در آزمون دیده شود.
نامگذاری مسیر اجازه میدهد بدون تکرار نشانی ثابت، آن را در پایتون یا قالب تولید کنید. فضای نام اپ جلوی برخورد نامهایی مثل detail در چند اپ را میگیرد. اگر بعداً پیشوند تغییر کند، تولید معکوس مسیر کمک میکند تعداد زیادی لینک دستی نشکند. خطای معکوسسازی معمولاً از نام، فضای نام یا آرگومان ناسازگار میآید.
from django.urls import reverse
url = reverse("pages:hello", kwargs={"name": "Sara"})
# /pages/hello/Sara/
برای نسخه تابعی همان فهرست، render درخواست، نام قالب و فرهنگ داده را میگیرد و پاسخ میسازد. کلیدهای داده در قالب قابل استفادهاند. اگر چیزی در صفحه ظاهر نمیشود، ابتدا نام کلید و نام قالب را بررسی کنید؛ تغییر بیهدف تنظیمات یا خاموش کردن حفاظت خروجی راه تشخیص مشکل نیست.
# add to pages/views.py
from django.shortcuts import render
from django.views.decorators.http import require_GET
@require_GET
def catalog(request):
context = {"title": "Catalog", "items": ["Book", "Notebook"]}
return render(request, "pages/catalog.html", context)
{# pages/templates/pages/catalog.html #}
<h1>{{ title }}</h1>
<ul>
{% for item in items %}
<li>{{ item }}</li>
{% empty %}
<li>No items</li>
{% endfor %}
</ul>
<a href="{% url 'pages:hello' name='Sara' %}">Hello</a>
اگر جستوجوی قالب بر اساس پوشه اپ را استفاده میکنید، قرار گرفتن اپ در فهرست نصبشده و فعال بودن تنظیم مربوط به قالب اپها را بررسی کنید. دوبار آمدن نام اپ در مسیر فایل عمدی است: پوشه بیرونی محل قالبهاست و پوشه داخلی فضای نام قالب را جدا میکند. این کار از برخورد دو فایل همنام در اپهای مختلف کم میکند.
گریز خودکار متغیرها را برای داده کاربر غیرفعال نکنید. افزودن فیلتر safe برای اینکه «ظاهر درست شود» میتواند محتوای ناامن را قابل اجرا کند. اگر واقعاً محتوای غنی لازم دارید، پاکسازی و سیاست مجاز بودن آن باید جدا طراحی شود. ویوی تابعی و کلاسی در این مسئولیت تفاوتی ندارند؛ انتخاب سبک ویو سد امنیتی ایجاد نمیکند.
| معیار | ویوی تابعی | ویوی کلاسی و عمومی |
|---|---|---|
| مسیر اجرای کد | معمولاً مستقیم و آشکار | میتواند بین متدها و کلاسهای پایه تقسیم شود |
| استفاده دوباره | تابع کمکی و دکوراتور | وراثت، میکسین و متدهای توسعه |
| شروع مناسب | منطق کوتاه یا خاص | الگوهای تکراری فهرست، جزئیات و فرم |
| خطر رایج | بزرگ شدن تابع و تکرار منطق | وراثت پیچیده و پنهان شدن رفتار |
| امنیت و کارایی | نیازمند طراحی و آزمایش | بهخودیخود امنتر یا سریعتر نیست |
برای endpoint خاصی که چند گام روشن دارد، تابع میتواند خواناتر باشد. برای چند صفحه مشابه فهرست یا جزئیات، ویوی عمومی تکرار را کم میکند. لازم نیست کل پروژه را فقط با یکی از این دو سبک بنویسید. قرارداد تیم، آزمونپذیری و قابلردگیری بودن رفتار از یکدست کردن ظاهری همه فایلها مهمتر است.
در کار با میکسینها، ترتیب وراثت و متد مورد توسعه را بفهمید. مرجع سیسیبیوی برای دیدن متدها و زنجیره کلاسهای ویوهای عمومی مفید است؛ اما نسخه انتخابی آن را با پروژه تطبیق دهید و مستندات رسمی را مرجع اصلی نگه دارید. کپی کردن یک میکسین بدون فهم دسترسی و فراخوانی والد میتواند رفتار ناخواسته ایجاد کند.
ابتدا بررسی کنید مسیر به ویوی موردنظر حل میشود، سپس وضعیت پاسخ و قالب را آزمایش کنید. در نمونه زیر از آزمون ساده جنگو استفاده میکنیم؛ این نمونه کد آموزشی است و در محیط آمادهسازی این مطلب اجرا نشده، پس قبل از ورود به پروژه خودتان آن را با ساختار واقعی اپ تطبیق دهید. خروجی مورد انتظار را با اجرای محلی تأیید کنید.
# pages/tests.py
from django.test import SimpleTestCase
from django.urls import resolve, reverse
from .views import CatalogView
class PagesTests(SimpleTestCase):
def test_catalog(self):
url = reverse("pages:catalog")
self.assertIs(resolve(url).func.view_class, CatalogView)
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, "pages/catalog.html")
self.assertContains(response, "Notebook")
خطای پیدا نشدن صفحه میتواند از پیشوند اشتباه یا ترتیب الگوها باشد؛ پیدا نشدن قالب معمولاً به محل فایل و تنظیمات مربوط است. اگر متد مجاز نباشد، پاسخ متفاوتی میگیرید و اگر نام مسیر اشتباه باشد، تولید لینک پیش از ارسال درخواست هم ممکن است خطا بدهد. این خطاها را با هم مخلوط نکنید؛ هرکدام در مرحله متفاوتی از مسیر رخ میدهند.

برای ویوهای دارای داده، مجوز و نبود رکورد را هم آزمایش کنید. دریافت یک شناسه معتبر نباید اجازه دسترسی به رکورد شخص دیگر بدهد. پرسوجوی داده باید با دامنه مجاز کاربر محدود شود. در فهرستهای واقعی، صفحهبندی و هزینه پرسوجوها را بررسی کنید؛ انتقال منطق به کلاس بدون این بررسی، مشکل کارایی را حل نمیکند.
پس از اجرای مثال، یک صفحه جزئیات واقعی اضافه کنید و رفتار نبود داده را مشخص کنید. بعد تفاوت تابع و ویوی عمومی را روی همان نیاز مقایسه کنید؛ مقایسه دو مسئله متفاوت نتیجه گمراهکننده میدهد. برای تمرین پرسشها به سؤالهای مصاحبه جنگو و آمادگی برای مصاحبه جنگو مراجعه کنید.
اگر از دستیار برنامهنویسی کمک میگیرید، نسخه، ساختار اپ و آزمون مورد انتظار را در درخواست بنویسید؛ پرامپتهای کدنویسی نمونه رویکرد را نشان میدهد. برای پروژه عملی نیز طراحی و توسعه وبسایت رادینو را بررسی کنید. هدف این است که چرخه درخواست را بفهمید، نه اینکه فقط صفحهای با کد کپیشده باز شود.
برنده مطلق نداریم. برای رفتار کوتاه و خاص، تابع میتواند روشنتر باشد؛ برای الگوهای تکراری، ویوی عمومی مناسب است. امنیت، سرعت و کیفیت به طراحی واقعی وابستهاند، نه صرف نام سبک.
بخش تطبیقیافته مسیر را جدا میکند و باقی مسیر را به تنظیمات اپ میسپارد. این کار تقسیم مسئولیت و تغییر پیشوند اپ را ساده میکند؛ خودش ویو اجرا نمیکند و جای نامگذاری مسیر نیست.
در تابع، فرهنگ داده را به render بدهید؛ در ویوی کلاسی مناسب، داده را در متد زمینه اضافه کنید و رفتار والد را نگه دارید. نام کلیدها باید با متغیرهای قالب هماهنگ باشد.
ویوی آماده برای الگوی متداول مثل قالب، فهرست، جزئیات و فرم است. با تنظیم ویژگیها و توسعه متدها شخصیسازی میشود، اما اگر منطق شما بسیار متفاوت است، اصرار بر آن میتواند فهم کد را سختتر کند.
اولی برای مسیرهای خوانا با مبدلهای مشخص مناسب است؛ دومی از عبارت منظم استفاده میکند. مبدل عدد میتواند مقدار را به عدد تبدیل کند، ولی گروههای عبارت منظم معمولاً رشته میفرستند. برای مسیر ساده، پیچیدگی غیرضروری عبارت منظم اضافه نکنید.
نظرات 0
برای ارسال نظر وارد حساب کاربری شوید.
هنوز نظری ثبت نشده؛ اولین نفر باشید.