【问题标题】:Django fixtures save with default valueDjango 固定装置使用默认值保存
【发布时间】:2014-11-01 16:13:50
【问题描述】:

我使用的是 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_atupdated_at 上得到一个错误。所以我必须指定每个字段的内容,即使我希望它是“自动的”。

documentation(为什么这是在 django admin 文档中?!),我知道 save() 方法没有被调用,所以这就是为什么我把所有东西都放入 @987654336 @ 方法不起作用。但是不应该启用/使用defaultauto_now* 功能吗?

处理夹具文件时,数据按原样保存到数据库中。不调用模型定义的 save() 方法,并且任何 pre_save 或 post_save 信号都将使用 raw=True 调用,因为实例仅包含模型本地的属性。例如,您可能希望禁用访问在夹具加载期间不存在的相关字段的处理程序,否则会引发异常

有没有办法“强制” Django 自动使用 defaultauto_now* 特性作为固定装置?我正在使用manage.py syncdb 创建所有表等。

我在 google 上搜索过堆栈溢出,但似乎找不到正确的搜索关键字。

UPDATE-1:以下google group discussion 表示对象以raw 模式保存,这意味着不考虑auto_now* 功能。我仍在寻找是否有办法将某些模型函数挂钩到 Django 夹具保存。

【问题讨论】:

  • 你能用数据迁移代替夹具吗?如果您稍后通过模式迁移更改模型,这还有一个优势,即它们可以继续工作。
  • 目前我的数据有点多,无法轻松切换到迁移。但我知道这是一种更好的方法。
  • 一个关于初始开发期间迁移的好问题stackoverflow.com/questions/5021800/…
  • IIUC,夹具的想法是您将一些记录从数据库保存到夹具,然后再次将其加载到另一个(或新创建的)数据库。因此,您要问的是与固定装置的设计背道而驰,这就是您遇到问题的原因。如果你想创建 new 记录,标准的方法是有一个(非常简单的)脚本从某个地方抓取数据并以标准方式创建和保存记录,即 MyModel.create(**data )。
  • @Rainy 不也是用初始数据预填充数据库吗? (就我而言,这就是我使用它们的原因)

标签: python django fixtures python-3.4 django-1.7


【解决方案1】:

解决方案是使用 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()

这样,无论您以何种方式创建模型(通过外壳、固定装置等),模型/数据都会被填充。

【讨论】:

    【解决方案2】:

    Automatically loading initial data fixtures is deprecated in Django 1.7。一种解决方案是通过您提到的信号。 我更喜欢的另一个方法是创建一个 python 脚本,您可以在其中创建所有需要的数据,然后在 shell 中执行它:

    python manage.py shell < create_initial_data.py
    

    【讨论】:

    • 我喜欢你建议的 python 脚本的想法!但就目前而言,我有太多数据无法轻松将其转换为该格式。
    • 这是不正确的:自动加载灯具在 1.7 中已被弃用。
    • Django Admin command 会更有意义
    【解决方案3】:

    我认为问题出在您输入default=uuid.uuid4() 时。括号太多了,因为它们暗示您将uuid.uuid4() 的结果传递给默认参数而不是函数本身,因此您应该输入default=uuid.uuid4

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-07-28
      • 1970-01-01
      • 1970-01-01
      • 2013-06-11
      • 2018-10-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多