我有一个具有唯一字段SessionCategory
的模型name
。 name
引用了该模型的某些关键实例;唯一的问题是name
在我们的内部仪表板中也是可编辑的,因此用户可以通过更改name
来无意间“破坏”这些引用。
为解决此问题,我想创建一个新字段name_slug
,它是name
的简化版本,也具有唯一的约束。我尝试执行以下操作:
from django.db import models
from django.utils.text import slugify
from django.db.models.signals import pre_save
from django.dispatch import receiver
class SessionCategory(models.Model):
name = models.CharField(max_length=255, unique=True)
name_slug = models.CharField(max_length=255, unique=True)
@receiver(pre_save, sender=SessionCategory)
def create_name_slug(sender, instance, **kwargs):
if not instance.name_slug:
instance.name_slug = slugify(instance.name)
我在其中添加了name_slug
唯一字段。问题是,如果我尝试python manage.py makemigrations
,会收到以下提示:
(venv) Kurts-MacBook-Pro-2:lucy-web kurtpeek$ python manage.py makemigrations
You are trying to add a non-nullable field 'name_slug' to sessioncategory without a default; we can't do that (the database needs something to populate existing rows).
Please select a fix:
1) Provide a one-off default now (will be set on all existing rows with a null value for this column)
2) Quit, and let me add a default in models.py
Select an option:
我在https://docs.djangoproject.com/en/dev/howto/writing-migrations/#migrations-that-add-unique-fields遇到了一个工作流,该工作流用于编写创建唯一字段的迁移。在该示例中,使用“通用”函数uuid.uuid4()
生成唯一字段。但是,就我而言,我需要访问特定实例的name
,就像我希望通过连接到pre_save
信号获得的那样。
如何创建此迁移并维护唯一约束?
答案 0 :(得分:3)
我认为RunPython
功能会为您提供帮助。
第1步。在添加name_slug
字段之前,您已经有迁移文件。然后使用name_slug = models.CharField(max_length=255, unique=True,null=True)
创建一个新的迁移文件。该文件将如下所示
app_name/migrations/0003_some_name.py
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('sample', '0006_sessioncategory'),
]
operations = [
migrations.AddField(
model_name='sessioncategory',
name='name_slug',
field=models.CharField(max_length=255, null=True, unique=True),
),
]
第二步。通过使用RunPython
如下添加自定义迁移脚本,
from __future__ import unicode_literals
from django.db import migrations, models
from django.utils.text import slugify
class Migration(migrations.Migration):
def forwards_func(apps, schema_editor):
SessionCategory = apps.get_model("sample", "SessionCategory")
for instance in SessionCategory.objects.all():
if not instance.name_slug:
instance.name_slug = slugify(instance.name)
instance.save()
def reverse_func(apps, schema_editor):
pass
dependencies = [
('sample', '0006_sessioncategory'),
]
operations = [
migrations.AddField(
model_name='sessioncategory',
name='name_slug',
field=models.CharField(max_length=255, null=True, unique=True),
),
migrations.RunPython(forwards_func, reverse_func
)
]
第3步。通过python manage.py migrate
进行迁移
而已 !
警告!
不要在第1步上运行 python manage.py migrate
命令(仅makemigrations
命令)
注意
迁移文件是在我的本地系统中生成的,用于重现行为。对于您来说,可能有所不同