我有一个 Django 模型,以前看起来像这样:
class Car(models.Model):
manufacturer_id = models.IntegerField()
还有另一种模型,称为
Manufacturer
,id
字段指的是。但是,我意识到使用 Django 的内置外键功能会很有用,因此我将模型更改为:
class Car(models.Model):
manufacturer = models.ForeignKey(Manufacturer)
此更改似乎立即工作正常,查询工作没有错误,但是当我尝试运行迁移时,Django 输出以下内容:
- Remove field manufacturer_id from car
- Add field manufacturer to car
执行此迁移会清除数据库中的所有现有关系,因此我不想这样做。我真的不想进行任何迁移,因为像
Car.objects.get(manufacturer__name="Toyota")
这样的查询工作正常。我想要一个适当的数据库外键约束,但这不是一个高优先级。
所以我的问题是:有没有办法进行迁移或其他方法,让我可以将现有字段转换为外键?我无法使用
--fake
,因为我需要在开发、产品和同事的计算机上可靠地工作。
可以进行数据迁移
我不确定,可能还有另一种解决方案,您可以将字段重命名为您想要的名称,然后将字段更改为新类型(进行迁移)
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
),
]
由于该字段不会收到任何真正的更改(也就是说,组合时发出的所有 SQL 实际上都是 noop),因此您可以简单地告诉 Django 根本不要运行任何 SQL,而只更改 python 中的模型状态。这就是您的模型迁移的样子
class Migration(migrations.Migration):
dependencies = [
('device', '0017_auto_20240723_0936'),
]
operations = [
migrations.SeparateDatabaseAndState(
state_operations=[
migrations.RemoveField(
model_name='car',
name='manufacturer_id',
),
migrations.AddField(
model_name='car',
name='manufacturer',
field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='device.SinglePhaseDevice'),
),
],
database_operations=[]
)
]
但请注意此操作的含义。您可以有效地更改模型,而无需运行任何实际的 DDL。在某些(损坏的)数据库配置中,该列表必须填充一些内容。需要额外注意、测试和审查,以确保
database_operations
确实是空的。
一个简单的验证方法
这两个 DDL 在功能上应该是等效的,除非字段顺序(因为 django 生成的 DDL 可能包含 REMOVE 字段语句,从而弄乱了字段顺序)。如果不是,请尝试向数据库操作添加一些
migrations.AlterField()
操作,直到它们彼此匹配。
我今天也遇到了同样的问题。 无需重命名现有字段或删除现有列即可完成。
...
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",
),
),
db_constraint
和 db_index
是否为 True
模型的 Car.manufacturer
字段上的 Car
。如果未设置字段,则 True 是默认值。./manage.py makemigrations
生成 AlterField
迁移,并在 Car.manufacturer_id
上具有所需的约束和索引。第一步不会影响数据库一致性,因为生成的 DDL 对于
IntegerField
和 ForeignKey
与 db_constaint=False
和 db_index=False
是相同的
第二次迁移添加了缺失的约束和索引。
您可以使用
./manage.py sqlmigrate app migration
命令来检查