Django alterfield migration to textfield fails [duplicate]
Миграция для пакета Django django-mail-queue
содержит следующее в соответствующей части:
migrations.AlterField(
model_name='mailermessage',
name='to_address',
field=models.TextField(db_index=True, verbose_name='To'),
),
Но на MySQL 9.0.1 (Django 5.1.5) это не удается со следующей ошибкой:
django.db.utils.OperationalError: (1170, "BLOB/TEXT column 'to_address'
used in key specification without a key length")
Есть идеи, почему? Я нашел закрытый отчет об ошибке для Django (несколько лет назад), в котором были проблемы с подобным запросом AlterField, но, похоже, это не связано.
Поле было создано в миграции 0001 следующим образом:
migrations.CreateModel(
name='MailerMessage',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False,
auto_created=True, primary_key=True)),
('subject', models.CharField(max_length=250, verbose_name='Subject', blank=True)),
('to_address', models.TextField(verbose_name='To')),
('bcc_address', models.TextField(verbose_name='BCC', blank=True)),
('from_address', models.EmailField(max_length=250, verbose_name='From')),
('content', models.TextField(verbose_name='Content', blank=True)),
('html_content', models.TextField(verbose_name='HTML Content', blank=True)),
('app', models.CharField(max_length=250, verbose_name='App', blank=True)),
('sent', models.BooleanField(default=False, verbose_name='Sent', editable=False)),
('last_attempt', models.DateTimeField(verbose_name='Last attempt',
null=True, editable=False, blank=True)),
],
options={
'verbose_name': 'Message',
'verbose_name_plural': 'Messages',
},
bases=(models.Model,),
),
В списке миграций нет других ссылок на это поле.
Предложенная ниже команда sqlmigrate
выдала следующий результат:
--
-- Alter field file_attachment on attachment
--
-- (no-op)
--
-- Alter field sent on mailermessage
--
CREATE INDEX `mailqueue_mailermessage_sent_5a2c49dd` ON `mailqueue_mailermessage` (`sent`);
--
-- Alter field to_address on mailermessage
--
CREATE INDEX `mailqueue_mailermessage_to_address_88fb3d2d` ON `mailqueue_mailermessage` (`to_address`);
Но я не знаю, решена ли проблема или она повторится в производстве.
Причина, по которой это происходит, заключается в том, что Django стремится быть независимым от диалекта SQL, но некоторые технические детали, касающиеся различных баз данных, пока не освещены.
В данном конкретном случае может ли база данных MySQL не индексировать поле VARCHAR(…)
, если максимальная длина довольно велика, или для TEXT
, где вообще нет ограничений. MySQL может добавить индекс для элементов, содержащих не более 255 символов.
The migration thus aims to add an index on the to_address
field, and that field can not be indexed in MySQL. The index is however strictly speaking not necessary to get the thing working. We can fake the migration [Django-doc], so that Django thinks we did the migration, whereas in reality, we did not. We can do this by first migrating up to 0007
, then fake 0008
, and finally run the rest of the migrations, like:
python3 manage.py migrate mailqueue 0007
python3 manage.py migrate --fake mailqueue 0008
python3 manage.py migrate mailqueue