Django fixture 保存默认值

8 投票
3 回答
2242 浏览
提问于 2025-04-20 11:03

我正在使用Django 1.7,遇到了一个关于数据填充的问题。

我希望Django能使用默认值,或者通过save()方法来创建那些没有指定的值。

以下是我现在的对象:

# File: uuidable.py
import uuid
from django.db import models
from django.utils.translation import ugettext_lazy as _


class Uuidable(models.Model):
    uuid = models.CharField(_('uuid'), blank=True,
                            null=False, unique=True,
                            max_length=64, default=uuid.uuid4())  # Tried here

    class Meta:
        abstract = True

    def save(self, *args, **kwargs):
        if self.pk is None:
            self.uuid = uuid.uuid4()  # Tried here also
        super().save(*args, **kwargs)

# File: timestampable.py
from django.db import models
from django.utils.translation import ugettext_lazy as _


class Timestampable(models.Model):
    created_at = models.DateTimeField(_('created at'), auto_now_add=True)
    updated_at = models.DateTimeField(_('updated at'), auto_now=True)

    class Meta:
        abstract = True

# File: post.py
from project.lib.models.timestampable import Timestampable
from project.lib.models.uuidable import Uuidable

class Post(Timestampable, Uuidable):
    title = models.CharField(_('title'), max_length=250, blank=False)
    content = models.TextField(_('content'))

    def __str__(self):
        return self.title

如你所见,当我生成一个新的Post()时,created_atupdated_atuuid的值会在调用save()时自动生成。但是当我使用数据填充时,就出现了以下错误:

[...]initial_data.yaml': Could not load post.Post(pk=None): UNIQUE constraint failed: post_post.uuid

如果我在数据填充文件中指定了uuid,那么就会在created_at上出现错误,然后是updated_at。所以我必须为每个字段指定内容,尽管我希望它们是“自动”的。

根据文档(这为什么在Django的管理文档里?!),我知道save()方法并没有被调用,这就是我放在save()方法里的内容不生效的原因。但是难道defaultauto_now*的功能不应该被启用或使用吗?

当处理数据填充文件时,数据会原样保存到数据库中。模型定义的save()方法不会被调用,任何pre_savepost_save信号都会以原始模式(raw=True)被调用,因为实例只包含模型本地的属性。例如,你可能想要禁用那些在数据填充加载时访问相关字段的处理程序,因为这些字段并不存在,这样会引发异常。

有没有办法“强制”Django在数据填充时自动使用defaultauto_now*的功能?我正在使用manage.py syncdb来创建所有的表等。

我在谷歌和Stack Overflow上搜索过,但似乎找不到合适的搜索关键词。

更新-1:以下的谷歌小组讨论提到对象是以raw模式保存的,这意味着auto_now*的功能没有被考虑。我仍在寻找是否有办法将某个模型函数挂钩到Django的数据填充保存过程中。

3 个回答

1

我觉得问题出在你写的 default=uuid.uuid4() 这部分。括号多了,因为它表示你把 uuid.uuid4() 的结果传给了默认参数,而不是把这个函数本身传进去。所以你应该改成 default=uuid.uuid4

2

在Django 1.7中,自动加载初始数据的功能已经不推荐使用了。你提到的一个解决办法是通过信号来实现。还有一个我更喜欢的方法是创建一个Python脚本,在里面生成所有需要的数据,然后在命令行中执行这个脚本:

python manage.py shell < create_initial_data.py
7

解决办法是使用 Django 的信号:

import uuid
from django.db import models
from django.utils.translation import ugettext_lazy as _
from django.db.models.signals import pre_save
from django.dispatch import receiver

class Uuidable(models.Model):
    uuid = models.CharField(_('uuid'), blank=True,
                            null=False, unique=True,
                            max_length=64, default=uuid.uuid4())

    class Meta:
        abstract = True

    @receiver(pre_save)
    def set_uuid_on_save(sender, instance, *args, **kwargs):
        if instance.pk is None:
            instance.uuid = uuid.uuid4()

这样一来,无论你通过什么方式创建模型(比如通过命令行、数据文件等),模型里的数据都会自动填充。

撰写回答