چگونه خطاهای رایج Django را سریع و اصولی رفع کنیم؟
چرا خطاهای Django در پروژههای واقعی تکرار میشوند و چگونه میتوان آنها را از ریشه، بدون patch موقتی و بدون آسیب به پایداری پروژه، برطرف کرد؟ راهنمای عملی مبتنی بر تجربه.
یک شب جمعه، ساعت یازده، پروژهای که دوشنبه باید دمو شود و سروری که بالا نمیآید. در مرورگر فقط یک پیام کوتاه: ImproperlyConfigured. چند سال بعد، در پروژهای دیگر، همین الگو تکرار شد؛ این بار NoReverseMatch. بعد از کار روی دهها پروژه جنگویی، برایم قطعی شده که خطاهای جنگو (Django) تصادفی نیستند. الگو دارند، خانواده دارند، و ریشهشان تقریباً همیشه در یک تصمیم اشتباه معماری یا یک وابستگی ناهماهنگ پنهان است.
چرا خطاهای Django اینقدر تکرار میشوند؟
Django یک فریمورک opinionated است. برخلاف Flask که تقریباً همهی تصمیمهای ساختاری را به شما واگذار میکند، Django مجموعهای از کنوانسیونها را از پیش تحمیل میکند: ساختار پروژه، نحوه تعریف اپها، مدیریت تنظیمات، ترتیب بارگذاری ماژولها، و حتی قراردادهای نامگذاری در مدل و URL. همین opinionated بودن، دلیل بزرگترین مزیت و همچنین بزرگترین منبع خطاهای Django است.
وقتی از کنوانسیونها تبعیت میکنید، همهچیز خودکار کار میکند. اما کوچکترین انحراف - یک نام اشتباه، یک فایل جابهجاشده، یا یک تنظیم فراموششده - باعث میشود فریمورک در نقطهای که انتظار ندارید، از کار بیفتد. این دقیقاً همان جایی است که خطاها سر برمیآورند.
سه ریشه اصلی برای تکرار خطاها در پروژههای واقعی دیدهام:
- انتظار متفاوت از واقعیت: توسعهدهنده فرض میکند Django خودش میفهمد؛ اما Django فقط چیزی را میفهمد که شما صریحاً گفته باشید. جادو در Django وجود ندارد؛ فقط کنوانسیون هست.
- محیطهای ناهمگون: کد در لوکال کار میکند، در staging خطا میدهد، روی production دوباره کار میکند. تفاوت نسخه پایتون، نسخه Django، متغیرهای محیطی، یا حتی نسخهی کتابخانههای جانبی، سهقلوی همیشگی خطاهای محیطی است.
- نبود چرخهی تشخیص سیستماتیک: وقتی خطا رخ میدهد، بهجای پیروی از یک روش قابل تکرار، در صفحات Stack Overflow سرگردان میشوید و patch موقتی میزنید. patch موقتی، دشمن شماره یک پایداری پروژه است.
برای عمیقتر شدن در ساختار کلی این فریمورک، راهنمای راهنمای کامل Django برای بکاند را بخوانید. آنجا معماری کلی، انتخابهای طراحی و مدل ذهنی درست برای کار با این فریمورک باز شده است.
خطاهای Django شبیه تب هستند: با مسکن پایین میآیند، اما تا وقتی علت را نکشید، هر فصل برمیگردند.
شش خانواده اصلی خطاها که بیشترین وقت را میگیرند
در تجربهی من روی دهها پروژه Django، خطاها را میتوان در شش خانواده طبقهبندی کرد. شناخت این خانوادهها، کلید تشخیص سریع است. وقتی پیامی در ترمینال یا مرورگر میبینید، اول مشخص کنید به کدام خانواده تعلق دارد. این کار نیمی از راهحل است، چون جهت جستجو و دیباگ را از ابتدا درست تعیین میکند.
- خطاهای پیکربندی (Configuration Errors): فریمورک بوت میشود ولی در وسط راه به تنظیمات نامعتبر برمیخورد.
- خطاهای Import: ماژولی که انتظار میرود وجود ندارد، یا در جای اشتباه قرار گرفته است.
- خطاهای دیتابیس: مهاجرتها (Migrations) هماهنگ نیستند، یا کوئریها به شکل نامنتظره عمل میکنند.
- خطاهای Template و URL: مسیرهای تعریفشده با آنچه در کد استفاده میشود، همخوان نیستند.
- خطاهای View و فرم: منطق view اشتباه است یا دادههای ورودی مطابق انتظار نیست.
- خطاهای امنیتی: CSRF، PermissionDenied، و SuspiciousOperation که نشان میدهند لایه امنیتی Django فعال است و کار خودش را میکند.
خطاهای پیکربندی و راهاندازی Django
ImproperlyConfigured
این خطا شاید پرتکرارترین پیام تازهکارها باشد، ولی خیلی از توسعهدهندههای حرفهای هم هر چند وقت یک بار به آن برمیخورند. Django در سطح بوت، اعتبارسنجیهای دقیقی انجام میدهد. اگر یکی از این موارد را نقض کنید، ImproperlyConfigured بالا میآید:
- نبود
SECRET_KEYیا خالی بودن آن - نبود
ROOT_URLCONFیا مسیر اشتباه آن - تنظیمات
INSTALLED_APPSناقص یا اشتباه - نبود
DATABASESیا تنظیمات اشتباه در آن - عدم تعریف
ALLOWED_HOSTSدر حالتDEBUG = False - فراخوانی
django.setup()در جای اشتباه
تشخیص: پیام خطا دقیقاً میگوید کدام تنظیم مشکل دارد. جمله را از آخر به اول بخوانید. معمولاً هستهی مشکل در سه-چهار کلمه آخر است.
راهحل: معمولاً استفاده از یک فایل تنظیمات مبتنی بر محیط (Environment-based Settings) مشکل را برای همیشه رفع میکند. اگر ساختار پروژه را تازه شروع میکنید، راهنمای Django برای پروژههای پایتونی الگوی استاندارد را نشان میدهد.
Verification: بعد از اصلاح، پروژه را با python manage.py check اجرا کنید. اگر پیامی برنگشت، تنظیمات معتبر است. برای اطمینان بیشتر، همان دستور را با --deploy هم اجرا کنید تا هشدارهای آمادهسازی production دیده شوند.
DisallowedHost
پیام خطا: Invalid HTTP_HOST header. دلیل: درخواست از هاستی میآید که در ALLOWED_HOSTS نیست. این خطا دو سناریو دارد:
- توسعهی لوکال: باید
localhostو127.0.0.1درALLOWED_HOSTSباشند. اگر از دامنهی ngrok یا مشابه استفاده میکنید، آن دامنه هم باید اضافه شود. - استقرار: دامنهی اصلی و زیردامنهها باید اضافه شده باشند. اگر پروژه پشت proxy یا load balancer است، باید هدرهای واقعی هم بررسی شوند.
نکتهی حرفهای: در محیط توسعه، اگر میخواهید همهی هاستها را بپذیرید، میتوانید از ALLOWED_HOSTS = ["*"] استفاده کنید. اما هرگز این مقدار را در production نگه ندارید. این یک نقص امنیتی جدی است که به حملات Host Header Injection باز میکند.
سادهترین راه نجات، معمولاً گرانترین راه آینده است. ستارهی ALLOWED_HOSTS در production یکی از همین دامهاست.
AppRegistryNotReady
پیام خطا: Apps aren"t loaded yet یا django.core.exceptions.AppRegistryNotReady. این خطا وقتی رخ میدهد که مدلی را قبل از بارگذاری اپلیکیشنها import کنید. مثلاً در فایل settings.py یا در یک ماژول که قبل از اپها بارگذاری میشود.
راهحل: import مدلها را به داخل تابع منتقل کنید، نه بالای فایل. الگوی درست:
def get_some_data():
from myapp.models import MyModel
return MyModel.objects.all()
Verification: پس از جابهجایی import، پروژه را با python manage.py runserver اجرا کنید و بررسی کنید که خطا برطرف شده باشد. اگر خطا باقی ماند، دنبال importهای سطح ماژول در فایلهای بالادست بگردید.
ImproperlyConfigured در تنظیمات اپها
یک حالت خاص که کمتر کسی از ابتدا میشناسد: وقتی یک اپ را در INSTALLED_APPS به شکل اشتباه اضافه میکنید. مثلاً اپ بهصورت myapp اضافه شده ولی اپ واقعی در مسیر apps.myapp قرار دارد. Django در بوت، هنگام apps.populate() به این ناسازگاری برمیخورد.
راهحل: مسیر دقیق اپ را در INSTALLED_APPS استفاده کنید. اگر از ساختار چند-پوشهای استفاده میکنید، نام app config یا مسیر کامل ماژول را وارد کنید. برای پروژههای بزرگ، استفاده از AppConfig سفارشی و default_auto_field مناسب توصیه میشود.
خطاهای Import و بارگذاری ماژول
ModuleNotFoundError
پیام خطا: No module named "X". این خطا سه ریشه اصلی دارد:
- پکیج واقعاً نصب نیست: راهحل
pip installیاpip install -r requirements.txt. - پکیج نصب است ولی در virtualenv دیگری: راهحل، بررسی
which pythonوwhich pipو فعالسازی درست virtualenv. این خطا در تیمهای چندنفره شایعتر از آن است که فکرش را میکنید. - مسیر پروژه در PYTHONPATH نیست: راهحل، اجرای پروژه از ریشه، یا افزودن مسیر به
sys.path.
برای درک عمیقتر این خطا در زبان پایتون، مقاله رفع خطای ModuleNotFoundError را ببینید.
ImportError و وابستگی دایرهای
پیام خطا: cannot import name "X" from "Y". این خطا با ModuleNotFoundError فرق دارد. یعنی ماژول پیدا شده، اما نام مورد نظر در آن نیست. دلایل:
- تایپو در نام تابع یا کلاس
- وابستگی دایرهای (Circular Import)
- نسخهی ناسازگار یک پکیج که API را تغییر داده
Circular Import رایجترین و مرموزترین شکل این خطاست. دو ماژول که به هم import میزنند، در بارگذاری اولیه به بنبست میخورند. تشخیص: دنبال importهای دوطرفه در پروژه بگردید. راهحل: انتقال import به داخل تابع، یا استفاده از الگوی Lazy Import.
# اشتباه - circular import
# file a.py
from b import get_b
def get_a():
return get_b()
# file b.py
from a import get_a
def get_b():
return get_a()
# درست - lazy import
# file a.py
def get_a():
from b import get_b
return get_b()
برای مبانی و تفاوتها، مقاله علت و رفع ImportError در پایتون را بخوانید.
وابستگی دایرهای، شبیه به ازدواج دو قهرمانی است که هر کدام منتظر بلند شدن دیگری است. تا یکی از آن دو، دست از import نکشد، بنبست ادامه دارد.
ImproperlyConfigured در Django REST Framework
اگر با DRF کار میکنید، یک خطای خاص ظاهر میشود: Cannot apply DjangoModelPermissions on a view that does not have .queryset or .get_queryset() method. ریشه، پیکربندی ناقص کلاس permission است. راهحل: queryset یا get_queryset() را در view تعریف کنید، یا از یک کلاس permission مناسب استفاده کنید.
خطاهای دیتابیس و مدلها
OperationalError: no such table
این خطا در چند سناریو ظاهر میشود:
- در تست: دیتابیس تست تازه ساخته شده و migrate نشده. راهحل: مطمئن شوید که در تست، migrations اجرا میشوند. اگر تستهای سریع میخواهید، از
--keepdbاستفاده کنید یاMIGRATION_MODULESرا در تست override کنید. - در production: migration اجرا نشده. راهحل:
python manage.py migrateروی محیط هدف. - در staging: دیتابیس از یک snapshot بازیابی شده که جدول جدید را ندارد.
نکتهی مهم: هرگز در production دستور makemigrations را بدون بررسی اجرا نکنید. در staging ابتدا خروجی را با --dry-run بررسی کنید.
برای مبانی دیتابیس، آموزش یادگیری MySQL از صفر نقطه شروع مطمئنی است. همچنین اگر خطاهای دیتابیس شما از لایه SQL میآید، خطاهای رایج MySQL فهرست جامعی از کدها و پیامها را دارد.
DoesNotExist و MultipleObjectsReturned
پیمایش مدلها در Django با دو استثنای خاص همراه است:
Model.DoesNotExistوقتیget()هیچ رکوردی پیدا نکندModel.MultipleObjectsReturnedوقتیget()بیش از یک رکورد پیدا کند
هر دو در ذات خود خطا نیستند؛ نشانهی این هستند که فرضهای شما با دادهها همخوان نیست. راهحلهای درست:
- جای
get()ازfilter().first()استفاده کنید اگر انتظار صفر یا یک رکورد دارید. - اگر
get()را لازم دارید، آن را در بلوکtry/exceptقرار دهید. - برای
MultipleObjectsReturned، شرط فیلتر را دقیقتر کنید یا در مدل،UniqueConstraintمناسب اضافه کنید.
Migration Conflicts
پیام خطا: Conflicting migrations detected. این خطا در تیمهای چندنفره بسیار رایج است. دو developer همزمان روی یک مدل کار میکنند و هر کدام migration خودشان را میسازند.
راهحل اصولی:
python manage.py makemigrations --mergeبرای ادغام- بررسی دستی فایلهای migration - مخصوصاً ترتیب عملیات
- اجرای
migrateو تست
راهحل پیشگیرانه: قبل از هر commit، makemigrations و migrate روی شاخه لوکال خودتان. بعد pull و دوباره migrate. اضافه کردن یک CI job که روی PR بررسی کند migrationها conflicting نیستند، این درد را تقریباً کامل حل میکند.
ValueError: Field expected a number but got
این خطا معمولاً در فرمها یا serializerها رخ میدهد. یعنی دادهای که به مدل میرسد، نوع اشتباه دارد. تشخیص: message خطا به شما میگوید کدام فیلد و چه مقداری. راهحل: validation در سطح فرم یا serializer اضافه کنید تا ورودیهای نامعتبر پیش از رسیدن به مدل رد شوند. این کار، لایهی دفاعی مهمی است که از خطاهای پنهان و پیچیدهتر جلوگیری میکند.
OperationalError: FATAL: too many connections
در پروژههای پربازدید یا در تستهای موازی، این خطا شایع است. ریشه: نشت اتصال (connection leak) یا نبود connection pooling مناسب. راهحل: تنظیم CONN_MAX_AGE در تنظیمات دیتابیس، استفاده از pgbouncer برای PostgreSQL، و اطمینان از اینکه اتصالها در سطح ترد بسته میشوند.
خطاهای Template و URL
TemplateDoesNotExist
پیام خطا: X.html not found. ریشههای رایج:
- مسیر اشتباه در
TEMPLATES["DIRS"]در settings - نبود اپ مربوطه در
INSTALLED_APPS - اشتباه در نام پوشه -
templateبهجایtemplates - نبود پوشهی
templatesدر ریشهی اپ یا نبود فایل مورد نظر
نکتهی ظریف: Django فایلهای template را در چند مسیر جستجو میکند. ترتیب جستجو را میتوانید در DEBUG با خطای رخداده ببینید. خود پیام خطا، لیست مسیرهای بررسیشده را چاپ میکند. این تنها جایی است که باید از پیام خطا بهعنوان مستندات واقعی استفاده کنید.
NoReverseMatch
پیام خطا: Reverse for "X" not found. این خطا در سه لایه رخ میدهد:
- در url tag داخل template
- در
redirect()داخل view - در
reverse()وreverse_lazy()در کد پایتون
دلایل رایج: تایپو در نام URL، اشتباه در ارسال پارامتر، و تغییر نام URL بدون بهروزرسانی همهی مراجع. رایجترین حالت: در url نام URL را انگلیسی نوشتید، در template فارسی. Django به حساسیت حروف هم اهمیت میدهد.
راهحل: برای URLهای پرکاربرد، از get_absolute_url در مدل استفاده کنید. این تضمین میکند که مرجع URL همیشه از یک نقطه مدیریت شود و تغییرات به همهی جاها سرایت کند.
Static Files Not Loading در DEBUG=False
در حالت DEBUG=False، معمولاً فایلهای static بارگذاری نمیشوند. دلیل: در این حالت Django فایلها را سرو نمیکند. راهحل: استفاده از WhiteNoise، یا تنظیم Nginx برای سرو مستقیم فایلهای static. قبل از هر راهحل، مطمئن شوید که collectstatic اجرا شده و فایلها در STATIC_ROOT قرار دارند.
Verification: بعد از تنظیم، درخواست HTTP برای یک فایل static بزنید و کد وضعیت را بررسی کنید. اگر 200 برگشت، تنظیمات درست است. اگر 404، مسیر یا permission اشتباه است.
خطاهای View، فرم و امنیت
CSRF Verification Failed
پیام خطا: Forbidden (403). CSRF verification failed. این خطا بیشتر وقتها گمراهکننده است. ریشههای رایج:
- فرم فاقد
{% csrf_token %}است - کوکی CSRF حذف یا مسدود شده - مثلاً توسط مرورگر کاربر یا بهدلیل same-site policy
- درخواست از دامنهی متفاوت با اختلاف پروتکل HTTP/HTTPS ارسال شده
- پشت proxy یا load balancer، Django هدر اصلی را نمیبیند
راهحل: تنظیم CSRF_TRUSTED_ORIGINS برای دامنههای قابل اعتماد. نکتهی مهم: هرگز @csrf_exempt را بهعنوان راهحل عمومی روی viewها نگذارید. این کار لایهی حفاظتی مهمی را حذف میکند و درگاه حمله CSRF را باز میگذارد.
ValidationError
این خطا در سه سطح ظاهر میشود:
- در فیلد مدل:
full_clean()روی instance - در فرم:
is_valid()برمیگرددFalse - در serializerهای DRF: خطای ساختارمند با کد
نکتهی حرفهای: ValidationError برای خطاهای کاربر است، نه باگ برنامه. بنابراین باید بهصورت خوانا به کاربر نمایش داده شود، نه در لاگ سرور. اگر ValidationError را در لاگ میبینید، احتمالاً منطق validation شما ناقص است.
RelatedObjectDoesNotExist
پیام خطا: User has no profile یا مشابه آن. این خطا وقتی رخ میدهد که به یک relation یکبهیک (OneToOne) دسترسی میزنید که هنوز ساخته نشده.
راهحلها:
- استفاده از
hasattrقبل از دسترسی - استفاده از
get_or_createبرای ساخت خودکار - استفاده از signal
post_saveبرای ساخت پروفایل هنگام ساخت کاربر
PermissionDenied
پیام خطا: 403 Forbidden. این خطا نشان میدهد Django درست کار میکند. کاربری که درخواست داده، مجوز لازم را ندارد. راهحل: بررسی permissions کاربر، بررسی منطق authorize در view، و اطمینان از اینکه login_required یا PermissionRequiredMixin در جای درست قرار دارند.
SuspiciousOperation
پیامهای SuspiciousOperation نشان میدهند که Django یک رفتار مشکوک را شناسایی کرده است. مثالها:
SuspiciousFileOperation: تلاش برای دسترسی به فایلی خارج ازMEDIA_ROOTDisallowedModelAdminLookup: درخواست مشکوک به adminDisallowedRedirect: تلاش برای redirect به دامنهی خارجی
نکتهی مهم: هرگز برای رفع این خطاها، این حفاظتها را غیرفعال نکنید. SuspiciousOperation یعنی یک لایه امنیتی واقعی جلوی یک رفتار مشکوک را گرفته است. اگر میبینید این خطا زیاد تکرار میشود، احتمالاً کد شما الگوی اشتباهی دارد، نه اینکه Django بیش از حد سختگیر است.
برای مرور جامع امنیت جنگو، مقاله بهترین روشهای امنیت Django را بخوانید.
SuspiciousOperation را بهعنوان مزاحم نبینید؛ آن نگهبانی است که فقط وقت واقعی سروصدا میکند.
ImproperlyConfigured در DRF
در Django REST Framework، خطای ImproperlyConfigured در چند نقطهی مشخص شایع است: نبود serializer_class در generic view، تنظیم ناقص authentication_classes، یا نبود queryset برای ModelViewSet. تشخیص، همان پیام دقیق DRF است. راهحل: از الگوی get_serializer_class() برای انتخاب پویا و از get_queryset() برای محدودسازی داده استفاده کنید.
TypeError در منطق View
گاهی خطاهای نوعی پایتون، درون منطق view رخ میدهند و در traceback بهعنوان خطای سطح پایتون دیده میشوند. مثال کلاسیک: NoneType object is not subscriptable وقتی یک فیلد نال از دیتابیس برمیگردد. راهحل اصولی: در سطح serializer یا model method، مقدار پیشفرض مناسب تعیین کنید، نه اینکه در view با شرطهای پراکنده پوشش دهید.
OperationalError: database is locked
در SQLite، این خطا شایع است. ریشه: تراکنش طولانی یا نوشتن همزمان. راهحل: برای SQLite، از timeout در تنظیمات استفاده کنید. اما اگر پروژه در production است، SQLite انتخاب اشتباهی برای بار نوشتن است و باید به PostgreSQL مهاجرت کنید. این خطا نشانهی درست انتخاب نکردن دیتابیس است، نه یک باگ کدی.
جدول تشخیص سریع خطاها
این جدول، خلاصهی تشخیص را در یک نگاه ارائه میدهد. در پروژههای واقعی، این جدول را در ویکی تیم بگذارید تا همه به آن دسترسی داشته باشند.
| خطا | خانواده | اولین جایی که باید نگاه کنید |
|---|---|---|
| ImproperlyConfigured | پیکربندی | settings.py و متغیرهای محیطی |
| DisallowedHost | پیکربندی | ALLOWED_HOSTS و CSRF_TRUSTED_ORIGINS |
| AppRegistryNotReady | پیکربندی | importهای سطح ماژول |
| ModuleNotFoundError | Import | virtualenv و requirements.txt |
| ImportError دایرهای | Import | importهای دوطرفه بین ماژولها |
| OperationalError (no such table) | دیتابیس | migrate و اتصال دیتابیس |
| Migration Conflicts | دیتابیس | شاخههای migration و merge |
| NoReverseMatch | URL | urls.py و نامهای URL |
| TemplateDoesNotExist | Template | TEMPLATES["DIRS"] و INSTALLED_APPS |
| CSRF Verification Failed | امنیت | csrf_token و CSRF_TRUSTED_ORIGINS |
| PermissionDenied | امنیت | permissions و decoratorها |
| SuspiciousOperation | امنیت | MEDIA_ROOT و مسیرهای فایل |
پرسشهای پرتکرار درباره خطاهای Django
چرا خطاهای Django در لوکال ظاهر نمیشوند اما در production بالا میآیند؟
پاسخ: چون سه چیز در لوکال و production یکسان نیستند. اول، مقدار DEBUG: در لوکال معمولاً True است و بسیاری از خطاها پنهان میشوند. دوم، ALLOWED_HOSTS که در لوکال شامل localhost است ولی در production نیاز به دامنه دارد. سوم، نسخهی پکیجها و متغیرهای محیطی. راهحل: staging را با تنظیمات نزدیک به production بسازید. الگوی درست در ساخت REST API با پایتون آمده است.
آیا خاموش کردن DEBUG برای دیباگ کردن درست است؟
پاسخ: بله، ولی فقط بهصورت موقت و در محیط staging. در production، DEBUG هرگز نباید True باشد. اگر با DEBUG=False خطا میگیرید، لاگهای سرور را بررسی کنید یا ابزارهایی مثل Sentry را فعال کنید. Django در DEBUG=True اطلاعات حساس را نمایش میدهد که در production خطر امنیتی جدی است.
چطور بفهمم خطا از Django است یا از پکیج جانبی؟
پاسخ: در traceback دقت کنید. اگر آخرین frame در پکیج جانبی است و پکیج از API داخلی Django استفاده کرده، اغلب مشکل از ناسازگاری نسخه است. راهحل: pip list و بررسی نسخهها با requirements اصلی پکیج. برای دیباگ عمیقتر، لاگ سطح DEBUG را موقتاً فعال کنید.
آیا خطاهای Django معمولاً از پایتون میآیند یا از خود فریمورک؟
پاسخ: تقریباً همیشه از یک سطح بالاتر میآیند. خطاهای سطح پایتون مثل TypeError، AttributeError، یا KeyError در منطق شما ریشه دارند، نه در Django. برای شناخت این خطاها، آموزش یادگیری پایتون از صفر را ببینید. خطاهای سطح جنگو معمولاً پیکربندی یا معماری را نشان میدهند.
چرا بعد از ارتقای نسخه Django، پروژه دیگر کار نمیکند؟
پاسخ: چون Django در نسخههای major، APIهای قدیمی را deprecate و حذف میکند. راهحل: قبل از ارتقا، changelog و release notes را بخوانید. از ابزارهایی مثل django-upgrade برای بهروزرسانی خودکار کد استفاده کنید. همیشه در staging ابتدا تست کنید.
چرا خطای Circular Import بعد از اضافه کردن یک import جدید رخ میدهد؟
پاسخ: چون import شما ترتیب بارگذاری ماژولها را تغییر داده و یک حلقهی قبلاً پنهان را آشکار کرده است. راهحل: import را به داخل تابع منتقل کنید، یا از string-based app label در ForeignKey استفاده کنید. برای درک عمیقتر، الگوهای بارگذاری در جنگو را مطالعه کنید.
چرا در تیمهای چندنفره، خطاهای migration اینقدر زیاد است؟
پاسخ: چون دو developer میتوانند بهطور همزمان migration بسازند که روی یک مدل اثر میگذارند. راهحل: قبل از هر commit روی مدل، pull از شاخه اصلی، و ادغام migrationها با makemigrations --merge. هرگز فایل migration تولیدشده را دستی ویرایش نکنید، مگر اینکه کاملاً به ساختار آن مسلط باشید.
کدام ابزارها برای ردیابی خطاهای production جنگو مناسب هستند؟
پاسخ: Sentry برای exception tracking، Prometheus و Grafana برای مانیتورینگ، و ELK Stack برای log aggregation. برای پروژههای کوچک، لاگهای فایل کافی است. اما در هر اندازه، لاگها باید ساختارمند باشند تا قابل جستجو باشند. برای مبانی معماری، بکاند چیست را ببینید.
آیا باید Exceptionها را در View خودم catch کنم یا بگذارم Django هندل کند؟
پاسخ: بستگی دارد. برای خطاهای غیرمنتظره، بگذارید Django هندل کند - از django.views.defaults استفاده کنید. برای خطاهای قابل پیشبینی مثل ValidationError یا DoesNotExist، در View catch کنید و پاسخ معنادار به کاربر برگردانید. الگوی اصولی مدیریت استثنا در مدیریت خطا در پایتون آمده است.
چرا بعد از فعالسازی HTTPS، خطاهای CSRF بیشتر شدهاند؟
پاسخ: چون Kubernetes یا proxy در جلوی اپ قرار دارد و Django نمیتواند پروتکل اصلی را تشخیص دهد. راهحل: تنظیم SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https") و اضافه کردن دامنه به CSRF_TRUSTED_ORIGINS با پیشوند https. بدون این تنظیم، Django درخواست HTTPS را بهعنوان HTTP میبیند و CSRF را رد میکند.
آیا استفاده از try/except در همه Viewها توصیه میشود؟
پاسخ: نه. try/except با دامنهی گسترده، خطاهای واقعی را پنهان میکند و دیباگ را سختتر میکند. تنها خطاهای قابل پیشبینی را catch کنید. خطاهای دیگر باید در لاگ ظاهر شوند و توسط ابزارهای مانیتورینگ دیده شوند.
تفاوت ImproperlyConfigured و ConfigurationError چیست؟
پاسخ: در Django، تنها ImproperlyConfigured وجود دارد. اگر خطای مشابهی با نام ConfigurationError میبینید، احتمالاً از یک پکیج جانبی میآید. الگوی تشخیص یکسان است: پیام دقیق خطا را بخوانید و اولین پارامتر نامعتبر را اصلاح کنید.
چرا بعد از فعالسازی CSRF_COOKIE_SECURE، کاربران لاگین نمیشوند؟
پاسخ: چون این تنظیم باعث میشود کوکی فقط روی HTTPS ارسال شود. اگر سایت شما HTTP است یا از پروکسی با هدر اشتباه استفاده میکند، کاربر نمیتواند لاگین کند. راهحل: مطمئن شوید سایت روی HTTPS است و SECURE_PROXY_SSL_HEADER درست تنظیم شده است.
آیا خطاهای Django همیشه در سرور رخ میدهند یا در مرورگر هم دیده میشوند؟
پاسخ: خطاهای سمت سرور مثل ImproperlyConfigured یا OperationalError در Django با صفحهی خطای مخصوص نمایش داده میشوند (اگر DEBUG=True باشد) یا در لاگ سرور ظاهر میشوند. خطاهای سمت مرورگر مثل CSRF Verification Failed در خود مرورگر دیده میشوند. برای دیباگ، همیشه به هر دو سمت نگاه کنید.
چطور میتوانم خطاهای Django را قبل از کاربر ببینم؟
پاسخ: سه لایهی دفاعی بگذارید. اول، Sentry برای گرفتن خطاهای production. دوم، CI job که تستها و python manage.py check --deploy را اجرا میکند. سوم، monitoring uptime برای اطلاع از downtime. با این سه لایه، تقریباً همیشه قبل از کاربر خبردار میشوید.
درسهای میدانی از دل خطاهای جنگو
خطاهای Django، در ظاهر متنوع، اما در باطن خانوادگیاند. اگر بخواهم در چند جمله خلاصه کنم، سه اصل تجربی برایم تعیینکننده بوده است:
اصل اول: پیام خطا را کامل بخوانید. نه فقط خط اول را. در نه مورد از ده مورد، پاسخ در سه خط آخر traceback است. توسعهدهندههای تازهکار عادت دارند سریع به سراغ جستجو در گوگل بروند، ولی خود Django، پیامهایش را با دقت طراحی کرده است. هر خطی که از traceback میخوانید، یک فرض پنهان را افشا میکند.
اصل دوم: تفاوت محیطها را بپذیرید. کدی که در لوکال کار میکند، ممکن است در staging خطا بدهد و در production باز کار کند. این نه جادو است و نه نفرین؛ تفاوت پیکربندی و وابستگیهاست. هر تغییر در محیط، باید با چکلیست بررسی شود. تفاوتهای محیطی، دلیل شماره یک خطاهایی است که فقط یک نفر از تیم میبیند.
اصل سوم: چرخهی تشخیص را مستند کنید. هر بار که خطایی رفع میکنید، در commit message یا یک فایل تیم بنویسید چطور پیدا شد. با گذشت زمان، الگوها روشن میشوند و سرعت تشخیص چند برابر میشود. تیمی که این کار را میکند، در شش ماه اول، زمان دیباگ خود را به نصف میرساند.
خطاهای Django بیشتر شبیه مربی هستند تا دشمن. هر خطا، یک فرض پنهان را افشا میکند. اگر با دقت گوش کنید، بعد از چند ماه، پروژههای بعدی شما با خطاهای کمتری متولد میشوند. این دقیقاً همان چیزی است که تجربه را از دانش جدا میکند: تشخیص الگو، نه فقط رفع علائم.
هدف این مقاله، تمامکردن فهرست خطاهای Django نبود. هدف، دادن یک چارچوب ذهنی بود که با آن بتوانید هر خطای جدیدی را سریع دستهبندی کنید، ریشهاش را پیدا کنید، و با یک راهحل پایدار بهجای patch موقتی رفعش کنید. وقتی این چارچوب را درونی کنید، خطاها از مزاحم به یک جریان عادی کار تبدیل میشوند.
اگر این خطاها را در یک پروژه واقعی دیدهاید و یکی از آنها وقت بیشتری از شما گرفته است، برایم جالب است بدانم کدام یک. تجربهتان را در دیدگاهها بنویسید؛ بهویژه اگر راهحل متفاوتی پیدا کردهاید که میتواند برای خواننده بعدی مفید باشد. 🐍