【问题标题】:How to add new field in model after custom migration which access model before new field?自定义迁移后如何在模型中添加新字段,在新字段之前访问模型?
【发布时间】:2021-12-09 06:34:28
【问题描述】:

我有自定义迁移文件,它在表用户中创建条目。 初始工作项目具有以下迁移:

 1. 001_initial.py # creates model with some fields
 2. 002_custom_user_data.py # adds data in "user" due some middle requirement after some time.

现在我想在此表中再添加一列作为“config_data”。 为此,我遵循了以下步骤:

 1. python manage.py makemigrations <app-name> # creates one more migration file` 003_add_config_data_field.py
 2. python manage.py migrate # raise an error

迁移命令引发以下错误。

      Applying my_user.001_initial.py... OK
      Applying my_user.002_custom_user_data.py ...Traceback (most recent call last):
  File "/home/myhome/.local/share/virtualenvs/myproject/lib/python3.9/site-packages/django/db/backends/utils.py", line 84, in _execute
    return self.cursor.execute(sql, params)
psycopg2.errors.UndefinedColumn: column my_user.config_data does not exist
LINE 1: ..., "my_user"."address",

这是因为迁移 002 尝试访问 my_user 表之前添加字段迁移(003)被迁移到表中,这正在提高 UndefinedColumn config_data 错误。

知道如何解决这个问题,因为这些迁移应该适用于新 DB 以及更早迁移到 002 的生产 DB。

以下是 002_custom_user_data.py 的迁移

# Generated by Django 3.2.2

from django.db import migrations
from myapp.models import MyUser


def create_user(apps, schema_editor):
    user = MyUser.objects.get_or_create(id=123)
    user.address = 'demo'
    user.save()


def delete_user(apps, schema_editor):
    MyUser.objects.filter(id=123).delete()


class Migration(migrations.Migration):

    dependencies = [
        ('my_user', '001_initial'),
    ]
    operations = [
    migrations.RunPython(create_user, delete_user, elidable=True)
]

谢谢。

【问题讨论】:

    标签: python-3.x django django-migrations


    【解决方案1】:

    您应该导入 historical 模型,而不是您当前的模型。 Django 会在您运行迁移之前跟踪模型的外观,您可以使用 apps.get_model(…) method [Django-doc] 访问此类模型:

    from django.db import migrations
    # No import from myapp.models!
    
    
    def create_user(apps, schema_editor):
        MyUser = apps.get_model('my_user', 'MyUser')
        user = MyUser.objects.get_or_create(id=123)
        user.address = 'demo'
        user.save()
    
    
    def delete_user(apps, schema_editor):
        MyUser = apps.get_model('my_user', 'MyUser')
        MyUser.objects.filter(id=123).delete()
    
    
    class Migration(migrations.Migration):
    
        dependencies = [
            ('my_user', '001_initial'),
        ]

    我们在这里使用的MyUser 模型本身不会具有您在models.py 中定义的所有字段,这些字段本身也不会具有相同的类型。因此,您可以像在那个时间点一样使用模型,从而定义数据迁移。例如,如果您添加了一个额外的字段,则稍后会更新记录。

    【讨论】:

    • 谢谢。 MyUser 模型上有 post_save 信号,由于 apps.get_model('my_user', 'MyUser') 没有被触发。如果我以正常方式从 my_user 应用程序导入这些模型,则信号有效。但不知何故无法调用答案中描述的 post_save 信号。知道出了什么问题吗?
    • 信号会在历史模型操作上触发吗?
    • @AkashPagar:不,触发器不会运行,您需要在同一数据迁移中实现触发器的逻辑。
    • 是的。这行得通。
    猜你喜欢
    • 2015-08-03
    • 2015-02-03
    • 2016-01-03
    • 1970-01-01
    • 2014-08-10
    • 1970-01-01
    • 2012-06-09
    • 2020-04-20
    • 1970-01-01
    相关资源
    最近更新 更多