仅更新模型中的特定字段。模型

问题描述 投票:0回答:3

我有模型

class Survey(models.Model):
    created_by = models.ForeignKey(User)
    question = models.CharField(max_length=150)
    active = models.NullBooleanField()
    def __unicode__(self):
        return self.question

现在我只想更新

active
字段。所以我这样做:

survey = get_object_or_404(Survey, created_by=request.user, pk=question_id)
survey.active = True
survey.save(["active"]) 

现在我收到错误

IntegrityError: PRIMARY KEY must be unique

我这个更新方法对吗?

django django-models django-views django-database
3个回答
282
投票

要更新字段子集,您可以使用

update_fields
:

survey.save(update_fields=["active"]) 

update_fields
参数是在 Django 1.5 中添加的。在早期版本中,您可以使用
update()
方法来代替:

Survey.objects.filter(pk=survey.pk).update(active=True)

22
投票

通常,更新一个或多个模型实例中某些字段的正确方法是在相应的查询集上使用

update()
方法。然后你做这样的事情:

affected_surveys = Survey.objects.filter(
    # restrict your queryset by whatever fits you
    # ...
    ).update(active=True)

这样,您就不再需要在模型上调用

save()
,因为它会自动保存。此外,
update()
方法还会返回受您的更新影响的调查实例的数量。


0
投票

您可以使用此 mixin,它可用于检测模型实例中哪些字段已更改,并将该信息传递给 save 方法。这是 mixin 的描述:

  • init 方法中,mixin 初始化一个名为 old_instance_data 的字典,该字典存储模型实例中字段的初始值。
  • 在 save 方法中,mixin 将字段的当前值与 old_instance_data 中存储的初始值进行比较,以确定哪些字段已更改。它创建一组 update_fields,其中包含已更改字段的名称。
  • 如果模型实例有主键(self.pk 不是 None),如果未显式提供 update_fields,mixin 会自动确定更改的字段。
  • mixin 然后调用父类的 save 方法,将 update_fields 以及可能提供的任何其他关键字参数传递给它。
  • 如果您在保存时传递自己的 update_fields 参数,则使用此参数。因此,您可以在代码中的任何位置部分使用其他 update_fields。

通过在模型中使用此mixin,您可以方便地跟踪并仅保存已修改的字段,这有助于优化数据库更新并减少不必要的数据库查询。

from django.db import models


class UpdateFieldsMixin(models.Model):
    """ Detects which field changed and passes it to save method """
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        fields = (field.name for field in self._meta.fields)
        self.old_instance_data = {name: getattr(self, name, None)
                                  for name in fields}

    def save(self, update_fields=None, **kwargs):
        if self.pk:
            update_fields = update_fields or {
                k for k, v in self.old_instance_data.items()
                if getattr(self, k, None) != v}
        return super().save(update_fields=update_fields, **kwargs)

    class Meta:
        abstract = True

像这样使用它:

class YourModel(UpdateFieldsMixin, models.Model):
    # Any code

    def save(**kwargs):
        # Any code
        return super().save(**kwargs)

仅此而已。如果您有自定义保存方法,请确保调用 UpdateFieldsMixin.save。我建议使用 super() 就像上面的例子一样。

© www.soinside.com 2019 - 2024. All rights reserved.