Django fixture 保存默认值
我正在使用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_at
、updated_at
和uuid
的值会在调用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()
方法里的内容不生效的原因。但是难道default
或auto_now*
的功能不应该被启用或使用吗?
当处理数据填充文件时,数据会原样保存到数据库中。模型定义的
save()
方法不会被调用,任何pre_save
或post_save
信号都会以原始模式(raw=True)被调用,因为实例只包含模型本地的属性。例如,你可能想要禁用那些在数据填充加载时访问相关字段的处理程序,因为这些字段并不存在,这样会引发异常。
有没有办法“强制”Django在数据填充时自动使用default
或auto_now*
的功能?我正在使用manage.py syncdb
来创建所有的表等。
我在谷歌和Stack Overflow上搜索过,但似乎找不到合适的搜索关键词。
更新-1:以下的谷歌小组讨论提到对象是以raw
模式保存的,这意味着auto_now*
的功能没有被考虑。我仍在寻找是否有办法将某个模型函数挂钩到Django的数据填充保存过程中。
3 个回答
我觉得问题出在你写的 default=uuid.uuid4()
这部分。括号多了,因为它表示你把 uuid.uuid4()
的结果传给了默认参数,而不是把这个函数本身传进去。所以你应该改成 default=uuid.uuid4
。
在Django 1.7中,自动加载初始数据的功能已经不推荐使用了。你提到的一个解决办法是通过信号来实现。还有一个我更喜欢的方法是创建一个Python脚本,在里面生成所有需要的数据,然后在命令行中执行这个脚本:
python manage.py shell < create_initial_data.py
解决办法是使用 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()
这样一来,无论你通过什么方式创建模型(比如通过命令行、数据文件等),模型里的数据都会自动填充。