وقتی روی یک پروژه جنگو (Django) کار میکنیم، ممکن است پس از ایجاد یک سری مایگریشن جدید، متوجه شویم که این تغییرات لازم نیست یا باعث ایجاد خطا شدهاند. در چنین حالتی معمولاً با دستور rollback مایگریشنها را به عقب برمیگردانیم. اما یک اتفاق آزاردهنده ممکن است رخ دهد:
بعضی ستونها در دیتابیس PostgreSQL همچنان باقی میمانند، حتی اگر جنگو به نسخه قبلی برگشته باشد.
این عدم همگامی میان Django ORM و PostgreSQL باعث خطاهایی مثل زیر میشود:
- `column "file_type" does not exist`
- `column "is_exclusive" does not exist`
- خطا هنگام دریافت داده (`SELECT`)
- خطا هنگام ذخیره (`INSERT` یا `UPDATE`)
در این مقاله قدمبهقدم توضیح میدهیم چطور این مشکل رخ میدهد و چگونه میتوان آن را بهصورت اصولی و ایمن حل کرد.
مشکل از کجا شروع شد؟
در مدل زیر که در اپلیکیشن downloads تعریف شده بود، فیلدهای جدیدی اضافه شد:
file_type = models.CharField(max_length=20)
is_exclusive = models.BooleanField(default=False)
مایگریشنها ساخته و روی دیتابیس اعمال شدند. اما بعداً تصمیم گرفته شد به مایگریشنهای قبلی بازگردیم و این ستونها حذف شوند.
مثل همیشه دستور rollback زده شد:
python manage.py migrate downloads 000X
جنگو برگشت عقب، اما PostgreSQL هنوز ستونها را نگه داشته بود.
شناسایی جدول و ستونهای اضافی
ابتدا وارد محیط دیتابیس شدیم:
python manage.py dbshell
و ساختار جدول downloads_file را بررسی کردیم:
\d downloads_file;
خروجی نشان داد:
- ستونهای اصلی مدل وجود دارند (مانند title, description, price)
- اما ستونهایی که در مدل فعلی حذف شدهاند هنوز در دیتابیس حضور دارند:
file_type
is_exclusive
این دو ستون دلیل اصلی خطا بودند.
چرا این اتفاق میافتد؟
زیرا Django هنگام rollback، تنها مایگریشنها را unapply میکند.
اما اگر مایگریشن برگشتی حاوی عملیات حذف ستون نباشد (Drop Column)، PostgreSQL هنوز ستونها را نگه میدارد.
به همین دلیل:
- ORM مدلها را بدون این ستونها انتظار دارد
- PostgreSQL ستونها را دارد
- نتیجه = تضاد و خطا
راهحل اصولی: حذف دستی ستونهای اضافی
از آنجا که این ستونها دیگر در مدل وجود ندارند و قرار نیست در آینده استفاده شوند، بهترین روش این است که آنها را در PostgreSQL حذف کنیم.
در محیط PostgreSQL:
ALTER TABLE downloads_file DROP COLUMN file_type;
ALTER TABLE downloads_file DROP COLUMN is_exclusive;
بعد بررسی مجدد:
\d downloads_file;
اکنون جدول با Model فعلی همتراز شده است.
همگامسازی مجدد Django و دیتابیس
بعد از حذف ستونها، برای اطمینان دستورهای زیر توصیه میشود:
python manage.py makemigrations
python manage.py migrate
python manage.py check
اگر همهچیز درست باشد، خطایی دریافت نخواهید کرد و پروژه بدون مشکل اجرا میشود.
نکته حرفهای (اختیاری)
اگر مایگریشنهایی که این ستونها را اضافه کرده بودند وسط کار حذف شدهاند یا دیگر قرار نیست وجود داشته باشند، بهتر است فایل مایگریشنشان را نیز پاکسازی کنید تا تاریخچه تمیز بماند:
rm downloads/migrations/00XX_add_file_type.py
و سپس:
python manage.py makemigrations
python manage.py migrate --fake-initial
جمعبندی
این مشکل یکی از رایجترین سناریوها هنگام توسعه با Django است. اگر مایگریشنها backward شوند اما ستونها در دیتابیس باقی بمانند، باید:
1. ساختار جدول را با `\d` بررسی کنید
2. ستونهای اضافی را شناسایی کنید
3. آنها را با `ALTER TABLE ... DROP COLUMN` حذف کنید
4. دوباره جنگو و دیتابیس را همگام کنید
پس از انجام این مراحل، پروژه بدون خطا و کاملاً منطبق با مدلهای فعلی اجرا خواهد شد.
نظرات کاربران (0)
هنوز نظری ثبت نشده است. اولین نفری باشید که نظر میدهید!