Django - 使用kwargs更新django模型对象中的字段

时间:2018-06-01 14:08:36

标签: python django django-models

我搜索了这个问题的简单答案但却找不到任何答案  This question有些看起来像,但不会退出,所以就在这里。

假设我的Django模型中有自定义更新方法。

class People(models.Model):
    identifier = models.CharField(max_length=255, primary_key = True)
    name = models.CharField(max_length=255)
    house = model.ForeignKey(House)
    salary = model.IntegerField()

    def my_fancy_update(self, **kwargs):
        # Here I want to do my update
        pass

我想要做的是使用kwargs来更新我的模型 现在我使用以下内容:

def my_fancy_update(self, **kwargs):
    self.name = kwargs.get('name')
    self.house = kwargs.get('house')
    self.salary = kwargs.get('salary')
    self.save()

这看起来像我真正想做的事情:

def my_fancy_update(self, **kwargs):
    self.update(**kwargs)

self.update不起作用会引发错误:
AttributeError: 'People' object has no attribute 'update'

由于使用self.objects.update时无法访问经理,因此无法self

我现在的问题是,如果这是可能的,以及如何在Django中完成。
它节省了我在实际模型中列出每个属性的大量时间。

2 个答案:

答案 0 :(得分:3)

请注意您当前的解决方案:

def my_fancy_update(self, **kwargs):
    self.name = kwargs.get('name')
    self.house = kwargs.get('house')
    self.salary = kwargs.get('salary')
    self.save()

非常脆弱,因为它可以将任何名称,住宅和工资设置为None

第一个干净的解决方案是使用for循环和设置:

def my_fancy_update(self, **kwargs):
    for name, value in kwargs.items():
        setattr(self, name, value)
    self.save()

但这仍然很脆弱,因为它没有检查传递的名称实际上是模型字段名称。更安全的实现将使用self._meta.get_fields()来检查:

def my_fancy_update(self, **kwargs):
    fieldnames = set(f.name for f in self._meta.get_fields())
    for name, value in kwargs.items():
        if name not in fieldnames:
            raise ValueError("%s is not a field of %s" % (name, type(self).__name__))
        setattr(self, name, value)
    self.save()

最后,如果没有更新任何内容,您可能希望避免调用save(),并且只提交实际更新的内容:

def my_fancy_update(self, **kwargs):
    if not kwargs:
        return

    fieldnames = set(f.name for f in self._meta.get_fields())
    updated = []
    for name, value in kwargs.items():
        if name not in fieldnames:
            raise ValueError("%s is not a field of %s" % (name, type(self).__name__))
        setattr(self, name, value)
        updated.append(name)
    self.save(update_fields=updated)

答案 1 :(得分:2)

我们可以遍历属性并更新值,然后调用.save()函数:

def my_fancy_update(self, **kwargs):
    for k, v in kwargs.items():
        setattr(self, k, v)
    self.save()

然而,这将手动设置属性,因此可能会附加一些信号,触发器等,以更新和清除值。

setattr(..)是一个Python函数,setattr(x, 'y', z)等同于x.y = z(请注意,我们将'y'作为setattr(..)中的字符串传递。

也无法更新related_field__attribute等属性