使用UUIDField作为主键时如何判断模型实例是否是新的

时间:2015-12-15 07:21:49

标签: python django uuid

我有一个需要进行后处理的模型(我生成了body字段的MD5。

models.py

class MyModel(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    body = models.TextField()
    md5 = models.CharField(max_length=32)
    ...

    def save(self, *args, **kwargs):
        if self.pk is None: # Only for create (edit disabled)
            self.md5 = get_md5(self.body)
            super(MyModel, self).save(*args, **kwargs)

问题是最终的块不会执行,因为我没有看到检查实例是否是新的方法:self.pk永远不会None因为之前填充了UUID节省。

我想知道处理这个问题的最佳做法是什么。

提前致谢。

更新

我能想到的唯一解决方案是直接调用数据库:

  1. 检查id是否存在
  2. 比较modifiedcreated字段,以判断它是否为编辑

4 个答案:

答案 0 :(得分:2)

修改

  

self.pk永远不会是None,因为在保存之前会填充UUID。

使用方法为新实例设置id,而不是为id设置默认值。

class MyModel(...):
    id = models.UUIDField(primary_key=True, default=None,...)

    def set_pk(self):
        self.pk = uuid.uuid4()

    def save(self, *args, **kwargs):
        if self.pk is None:
            self.set_pk()
            self.md5 = get_md5(self.body)
            super(MyModel, self).save(*args, **kwargs)

答案 1 :(得分:1)

正如我已经回答here一样,我发现的最简洁的解决方案并不需要任何额外的datetime字段或类似的修补工具来插入Django的post_save信号。将其添加到 models.py

from django.db.models.signals import post_save
from django.dispatch import receiver

@receiver(post_save, sender=MyModel)
def mymodel_saved(sender, instance, created, **kwargs):
    if created:
        # do extra work on your instance
        self.md5 = get_md5(self.body)

此回调将阻止save方法,因此无论您是否使用表单或Django REST,您都可以执行诸如触发通知或在通过网络发回响应之前更新模型等操作AJAX调用的框架。当然,负责任地使用并将繁重的任务卸载到作业队列而不是让用户等待:)

答案 2 :(得分:0)

看起来最干净的方法是通过继承抽象模型来确保所有模型都有created日期,然后您只需检查created是否有值:< / p>

<强> models.py

class BaseModel(models.Model):
    """
    Base model which all other models can inherit from.
    """
    id = fields.CustomUUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    created = models.DateTimeField(auto_now_add=True)
    modified = models.DateTimeField(auto_now=True)

    class Meta:
        # Abstract models are not created in the DB
        abstract = True

class MyModel(BaseModel):
    my_field = models.CharField(max_length=50)

    def save(self, *args, **kwargs):
        if self.created:
            # Do stuff
            pass
        super(MyModel, self).save(*args, **kwargs)

答案 3 :(得分:0)

我在项目中遇到了同样的问题,发现可以检查模型实例的内部状态:

def save(self, *args, **kwargs):
    if self._state.adding: # Only for create (edit disabled)
        self.md5 = get_md5(self.body)
        super(MyModel, self).save(*args, **kwargs)

但是此解决方案依赖于内部实现,并且在Django更新后可能会停止工作