'Django change an existing field to foreign key
I used to have a model like this:
class Car(models.Model):
manufacturer_id = models.IntegerField()
There is another model Manufacturer
that the id
field refers to. However, I realized that it would be useful to use django's built-in foreign key functionality, so I changed the model to this:
class Car(models.Model):
manufacturer = models.ForeignKey(Manufacturer)
This actually works fine immediately, queries work without errors, everything is great, except that if I try to run migrations, Django outputs the following:
- Remove field manufacturer_id from car
- Add field manufacturer to car
Doing this migration would clear all the existing relationships in the database, so I don't want to do that. I don't really want any migrations at all, since queries like Car.objects.get(manufacturer__name="Toyota")
work fine. I would like a proper database foreign key constraint, but it's not a high priority.
So my question is this: Is there a way to make a migration or something else that allows me to convert a existing field to a foreign key? I can't use --fake
since I need to reliably work across dev, prod, and my coworkers computers.
Solution 1:[1]
You can do data migration
- add new field
- do a data migration https://docs.djangoproject.com/en/3.1/topics/migrations/#data-migrations
- remove old field
I am not sure, there might be another solution where you can rename the field to name you want to, then alter the filed to new type (do a migration)
operations = [
migrations.RenameField(
model_name='car',
old_name='manufacturer_id',
new_name='manufacturer',
),
migrations.AlterField(
model_name='car',
name='manufacturer',
field=ForeignKey(blank=True, null=True,
on_delete=django.db.models.deletion.CASCADE
),
]
Solution 2:[2]
I've faced the same issue today. Can be done without renaming an existing field or dropping existing column.
- Update the initial migration with CreateModel operation
...
migrations.CreateModel(
name="Car",
fields=[
(
"manufacturer",
models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.DO_NOTHING,
db_constraint=False,
db_index=False,
to="Manufacturer",
),
),
- Check that
db_constraint
anddb_index
areTrue
onCar.manufacturer
field ofCar
model. True is a default value if the fields not set. - Run
./manage.py makemigrations
that generatesAlterField
migration with required constraint and index onCar.manufacturer_id
.
The first step won't effect db consistency because the generated DDL will be the same for IntegerField
and ForeignKey
with db_constaint=False
and db_index=False
and the second migration adds missing constraint and index.
You can check that with ./manage.py sqlmigrate app migration
command
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | mousetail |
Solution 2 |