【问题标题】:Django migration default value callable generates identical entryDjango迁移默认值可调用生成相同的条目
【发布时间】:2017-07-18 17:02:28
【问题描述】:

我正在向现有数据库表添加一个新字段。它是用字符串自动生成的。
这是我的代码:

from django.utils.crypto import get_random_string

...
Model:
    verification_token = models.CharField(max_length=60, null=False, blank=False, default=get_random_string)

我使用./manage.py makemigrations 生成我的迁移文件,并生成了一个文件。 我验证新文件的默认设置为field=models.CharField(default=django.utils.crypto.get_random_string, max_length=60)

所以一切看起来都很好。
继续./manage.py migrate,终端没有错误。 但是,当我检查我的表格时,我看到所有 token 字段都填充了相同的值。

这是我做错了吗? 如何在迁移中解决此问题?

【问题讨论】:

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


    【解决方案1】:

    当一个新的列被添加到一个表中,并且该列是NOT NULL 时,该列中的每个条目必须在该列的创建过程中填充一个有效值。 Django 通过在列定义中添加一个DEFAULT 子句来做到这一点。由于这是整个列的单个默认值,因此您的函数只会被调用一次。

    您可以使用数据迁移为列填充唯一值。 in the documentation 描述了一个稍微不同的用例的过程,但数据迁移的基础知识如下:

    from django.db import migrations, models
    from django.utils.crypto import get_random_string
    
    def generate_verification_token(apps, schema_editor):
        MyModel = apps.get_model('myapp', 'MyModel')
        for row in MyModel.objects.all():
            row.verification_token = get_random_string()
            row.save()
    
    class Migration(migrations.Migration):
    
        dependencies = [
            ('myapp', '0004_add_verification_token_field'),
        ]
    
        operations = [
            # omit reverse_code=... if you don't want the migration to be reversible.
            migrations.RunPython(generate_verification_token, reverse_code=migrations.RunPython.noop),
        ]
    

    只需将其添加到新的迁移文件中,更改 apps.get_model() 调用并更改依赖项以指向应用程序中的先前迁移。

    【讨论】:

    • 我最终使用了这个并解决了一些关于 Django 迁移的问题。谢谢,
    【解决方案2】:

    可能是要排序的token字符串,所以django会保存一些重复值。但是,我不确定这是你的主要问题。

    无论如何,我建议您使用while 处理重复值,然后通过生成的令牌过滤您的模型,确保尚未使用该令牌。我给你举个例子,比如下面..

    from django.utils.crypto import get_random_string
    
    def generate_token():
        token = get_random_string()
        number = 2
        while YourModel.objects.filter(verification_token=token).exists():
            token = '%s-%d' % (token, number)
            number += 1
        return token
    

    在你的领域verification_token;

    verification_token = models.CharField(max_length=60, unique=True, default=generate_token)
    

    我还建议您使用unique=True 来处理重复值。

    【讨论】:

    • 虽然由于 django 迁移对所有现有行使用一个默认值,这不起作用,但我还是朝着正确的方向前进。
    猜你喜欢
    • 1970-01-01
    • 2017-03-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-30
    • 2021-08-18
    • 2023-01-01
    • 2020-07-26
    相关资源
    最近更新 更多