gpt4 book ai didi

python - 如何为两个相关模型组织迁移并自动为新建对象的 id 设置默认字段值?

转载 作者:太空狗 更新时间:2023-10-30 01:17:54 26 4
gpt4 key购买 nike

假设有一个生产数据库,里面有一些数据。我需要在下一个棘手的案例中迁移。

有一个模型(已经在数据库中),比如 Model,它有其他模型的外键。

class ModelA: ...
class ModelX: ...

class Model:
  a = models.ForeignKey(ModelA, default = A)
  x = models.ForeignKey(ModelX, default = X)

并且我们需要再创建一个模型ModelYModel 应该引用它。并且在创建 Model 时,一个对象应该有一些与某个 ModelY 对象相关的默认值,这显然还不可用,但我们应该在迁移期间创建它。

class ModelY: ...
class Model:
  y = models.ForeignKey (ModelY, default = ??????)

所以迁移顺序应该是:

  • 创建ModelY
  • 在此表中创建一个默认对象,将其 id 放在某处
  • Model表中新建字段y,取默认值来自上一段

当然,我想将所有这些自动化。因此,为了避免手动应用一个迁移,然后创建一些对象,然后记下它的 ID,然后使用这个 ID 作为新字段的默认值,然后才用这个新字段应用另一个迁移。

而且我也想一步完成,所以在旧模型中同时定义 ModelY 和一个新字段 y,生成迁移,修复它以某种方式,然后立即申请并使其发挥作用。

这种情况有什么最佳做法吗?特别是,在哪里存储这个新创建的对象的 id?同一个数据库中的一些专用表?

最佳答案

您无法在单个迁移文件中执行此操作,但您可以创建多个迁移文件来实现此目的。我会尽力帮助您,但我不确定这是否是您想要的,它应该会教您一两件关于 Django 迁移的事情。

我将在这里提及两种类型的迁移,一种是架构迁移,这些是您通常在更改模型后生成的迁移文件。另一个是数据迁移,这些需要使用--empty 创建。 makemigrations 的选项命令,例如python manage.py makemigrations my_app --empty , 并用于移动数据、设置需要更改为非空的空列上的数据等。

class ModelY(models.Model):
# Fields ...
is_default = models.BooleanField(default=False, help_text="Will be specified true by the data migration")

class Model(models.Model):
# Fields ...
y = models.ForeignKey(ModelY, null=True, default=None)

您会注意到 y接受 null,我们稍后可以更改它,现在您可以运行 python manage.py makemigrations生成架构迁移。

要生成您的第一个数据迁移,请运行命令 python manage.py makemigrations <app_name> --empty .您会在迁移文件夹中看到一个空的迁移文件。您应该添加两种方法,一种将创建您的默认值 ModelY实例并将其分配给您现有的 Model实例,另一个将是 stub 方法,因此 Django 将允许您稍后在需要时撤消迁移。

from __future__ import unicode_literals

from django.db import migrations


def migrate_model_y(apps, schema_editor):
"""Create a default ModelY instance, and apply this to all our existing models"""
ModelY = apps.get_model("my_app", "ModelY")
default_model_y = ModelY.objects.create(something="something", is_default=True)

Model = apps.get_model("my_app", "Model")
models = Model.objects.all()
for model in models:
model.y = default_model_y
model.save()


def reverse_migrate_model_y(apps, schema_editor):
"""This is necessary to reverse migrations later, if we need to"""
return


class Migration(migrations.Migration):

dependencies = [("my_app", "0100_auto_1092839172498")]

operations = [
migrations.RunPython(
migrate_model_y, reverse_code=reverse_migrate_model_y
)
]

不要直接将您的模型导入此迁移!模型需要通过apps.get_model("my_app", "my_model")返回方法,以便获得此迁移时间点的模型。如果将来您添加更多字段并运行此迁移,您的模型字段可能与数据库列不匹配(因为模型来自 future ,有点......),并且您可能会收到一些关于数据库中缺少列的错误,并且这样的。还要注意在迁移中对模型/管理器使用自定义方法,因为您无法从此代理模型访问它们,通常我可能会将一些代码复制到迁移中,因此它始终运行相同。

现在我们可以回去修改Model型号保证y不为空,它会选择默认值 ModelY future 的例子:

def get_default_model_y():
default_model_y = ModelY.objects.filter(is_default=True).first()
assert default_model_y is not None, "There is no default ModelY to populate with!!!"
return default_model_y.pk # We must return the primary key used by the relation, not the instance

class Model(models.Model):
# Fields ...
y = models.ForeignKey(ModelY, default=get_default_model_y)

现在你应该运行python manage.py makemigrations再次创建另一个架构迁移。

您不应该混合架构迁移和数据迁移,因为迁移包装在事务中的方式可能会导致数据库错误,这会提示尝试在事务中创建/更改表和执行 INSERT 查询。

最后你可以运行 python manage.py migrate它应该创建一个默认的 ModelY 对象,将它添加到模型的 ForeignKey 中,并删除 null使其成为默认的 ForeignKey。

关于python - 如何为两个相关模型组织迁移并自动为新建对象的 id 设置默认字段值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56397090/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com