خطای Specified key was too long در جنگو
خطای "Specified key was too long" در Django معمولاً زمانی رخ می دهد که شما بخواهید از یک کلید (Key) برای ایندکس کردن فیلدی خاص در پایگاه داده استفاده کنید و طول این کلید از محدودیتهایی که پایگاه داده (مانند MySQL یا PostgreSQL) برای طول کلید ایندکس در نظر گرفته است، بیشتر باشد. خطا مذکور اغلب زمانی رخ میدهد که از پایگاه داده MySQL استفاده میکنید. در حالت پیشفرض، محدودیت طول کلید ایندکس از 767 بایت نباید تجاوز نماید.
برای حل این مشکل راه حل های متعددی وجود دارد که در ادامه به آنها پرداخته می شود:
-
کاهش طول فیلدهای CharField
اگر فیلدی دارید که طول آن بزرگتر از مقدار معمول (255) است و با unique=True یا index=True مشخص شده، طول آن را کاهش دهید:
class MyModel(models.Model):
name = models.CharField(max_length=191, unique=True)
در واقع max_length برابر با 191 در نظر گرفته می شود. MySQL برای هر کاراکتر در utf8mb4، چهار بایت در نظر میگیرد و محدودیت 767 بایت برای کلیدهای ایندکس وجود دارد. بنابراین، 191 کاراکتر (191 * 4 = 764 بایت) در محدوده مجاز قرار خواهد گرفت.
-
تنظیم Collation پایگاه داده
اگر نیاز به utf8mb4 ندارید، میتوانید از utf8 استفاده کنید که سه بایتی است. بدین منظور:
-
فایل settings.py موجود در مسیر پروژه خود را باز کنید.
-
در بخش مربوط به تنظیمات پایگاه داده، گزینه OPTIONS را به صورت زیر اضافه کنید:
'OPTIONS': {
'charset': 'utf8',
},
-
تغییر جدول در MySQL
میتوانید با استفاده از قطعه کد زیر در دیتابیس خود، جداول را تغییر دهید:
ALTER TABLE your_table_name CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;
نکته: در قطعه کد فوق، your_table_name نام جدول شما است.
در این صورت نیاز است تا ابتدا وارد "phpMyAdmin" از بخش "DATABASES" شوید.
در این صورت نیاز است تا ابتدا وارد "phpMyAdmin" از بخش "DATABASES" شوید.
.webp)
تصویر(1)
سپس دیتابیس مد نظرتان را انتخاب کرده (شماره1)، وارد تب "SQL" شده (شماره2) و قطعه کد فوق را در آن قرار دهید (شماره3) و نهایتا برای اجرای دستور روی دکمه "Go" (شماره4) کلیک نمایید.
.webp)
تصویر(2)
-
استفاده از طول ایندکس در فیلدها
اگر نمیتوانید طول فیلد را کاهش دهید، از گزینه db_index یا index_together به همراه محدود کردن طول استفاده کنید:
class MyModel(models.Model):
name = models.CharField(max_length=250)
class Meta:
indexes = [
models.Index(fields=['name'], name='name_idx', max_length=191),
]
بعد از اعمال تغییرات می بایست مایگریشنهای قبلی حذف شوند تا مایگریشن های جدید ایجاد گردند.
به همین جهت وارد ترمینال شده و در مسیر مربوط به پروژه با وارد نمودن هر کدام از دستورات زیر به صورت مجزا، مایگریشنها و کش مربوط به مایگریشنها (محتویات فولدر _pycache_) را حذف نمایید.
find . -path "*/migrations/*.py" -not -name "__init__.py" -delete
find . -path "*_pycache_*.pyc" -delete
برای جلوگیری از بروز خطای وجود جداول مشابه، حتما پیش از انجام مجدد عملیات migrate تمامی جداول دیتابیس را مطابق با تصویر زیر، با انتخاب نام دیتابیس (شماره1) و سپس علامت زدن کلیه جداول (شماره2) و انتخاب گزینه "Drop" (شماره3) حذف کنید.
.webp)
تصویر(3)
در ادامه نیز برای migrate مجدد در ترمینال دستور زیر را وارد نمایید:
python manage.py migrate