Hey guys!
I found some interesting bug today.
I created two models: Document model and Language model.
This is a Language model:
class Language(models.Model):
"""
Document language model
"""
code = models.CharField(blank=False, max_length=2)
label = models.CharField(blank=False, max_length=40)
And this is a Document model:
class Document(AbstractModel):
"""
Document model
"""
title = models.CharField(max_length=300, blank=False)
author = models.CharField(max_length=300, blank=False)
...
created_by = models.ForeignKey(User, related_name='documents',
on_delete=models.PROTECT)
languages = models.ManyToManyField(Language, blank=True)
And then I ran makemigrations. This is migration file’s content:
class Migration(migrations.Migration):
initial = True
dependencies = [
...
]
operations = [
...
migrations.CreateModel(
name='Document',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(max_length=300)),
('author', models.CharField(max_length=300)),
...
('created_by', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='documents', to=settings.AUTH_USER_MODEL)),
],
options={
'verbose_name': 'Document',
'verbose_name_plural': 'Documents',
},
),
migrations.CreateModel(
name='Language',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('code', models.CharField(max_length=2)),
('label', models.CharField(max_length=40)),
],
options={
'verbose_name': 'Language',
'verbose_name_plural': 'Languages',
},
),
...
migrations.AddField(
model_name='document',
name='languages',
field=models.ManyToManyField(blank=True, to='documents.Language'),
),
]
After that I decided to make the code field a primary key in a Language model:
class Language(models.Model):
"""
Document language model
"""
code = models.CharField(blank=False, max_length=2, primary_key=True)
label = models.CharField(blank=False, max_length=40)
And I ran makemigrations again. This is second migration file’s content:
class Migration(migrations.Migration):
dependencies = [
...
]
operations = [
migrations.RemoveField(
model_name='language',
name='id',
),
migrations.AlterField(
model_name='language',
name='code',
field=models.CharField(max_length=2, primary_key=True, serialize=False),
),
]
Now we have code field as primary key for Language model. And it’s type is a char. But let’s look at the model document_document_language (It created automatically):
document_document_languages:
id integer
document_id integer
language_id integer
You can see that the relationship between models is maintained through an identifier that is no longer in the Language model (language_id is integer).
As result we have SQL error when we trying to create m2m relationship between this models:
django.db.utils.ProgrammingError: operator does not exist: character varying = integer
LINE 1: ...cument_languages" ON ("documents_language"."code" = "documen...
If we remove the last two migration files and rerun makemigrations that problem will be solved:
document_document_languages:
id integer
document_id integer
language_id char
So help me figure it out, please. What is it?
It’s a really bug in Django or it’s my wrong action’s result?
If it’s the result of my wrong actions, tell me how to avoid similar problems in the future?
Sometimes you have to change the model after a long time, and then it is impossible to delete all these migrations.
I’m using Django 3.1, thanks.