Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/database/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何使用字典更新Django模型中的字段?_Python_Database_Django - Fatal编程技术网

Python 如何使用字典更新Django模型中的字段?

Python 如何使用字典更新Django模型中的字段?,python,database,django,Python,Database,Django,假设我有一个这样的模型: class Book(models.Model): num_pages = ... author = ... date = ... 我可以创建一个字典,然后使用它插入或更新模型吗 d = {"num_pages":40, author:"Jack", date:"3324"} 使用**创建新模型。循环浏览字典并使用setattr()更新现有模型 来自Tom Christie的Django Rest框架 下面是使用字典d创建的示例: Book

假设我有一个这样的模型:

class Book(models.Model):
    num_pages = ...
    author = ...
    date = ...
我可以创建一个字典,然后使用它插入或更新模型吗

d = {"num_pages":40, author:"Jack", date:"3324"}

使用
**
创建新模型。循环浏览字典并使用
setattr()
更新现有模型

来自Tom Christie的Django Rest框架


下面是使用字典d创建的示例:

Book.objects.create(**d)
要更新现有模型,需要使用QuerySet
filter
方法。假设您知道要更新的书籍的
pk

Book.objects.filter(pk=pk).update(**d)

如果您知道要创建它,请执行以下操作:

Book.objects.create(**d)
假设您需要检查现有实例,您可以使用get或create找到它:

instance, created = Book.objects.get_or_create(slug=slug, defaults=d)
if not created:
    for attr, value in d.items(): 
        setattr(instance, attr, value)
    instance.save()
正如在另一个答案中提到的,您也可以使用queryset管理器上的
update
功能,但我相信它不会发出任何信号(如果您不使用它们,这对您来说可能无关紧要)。但是,您可能不应该使用它来更改单个对象:

Book.objects.filter(id=id).update()

在其他答案的基础上,添加一个更安全的版本,以防止弄乱相关字段:

def is_simple_editable_field(field):
    return (
            field.editable
            and not field.primary_key
            and not isinstance(field, (ForeignObjectRel, RelatedField))
    )

def update_from_dict(instance, attrs, commit):
    allowed_field_names = {
        f.name for f in instance._meta.get_fields()
        if is_simple_editable_field(f)
    }

    for attr, val in attrs.items():
        if attr in allowed_field_names:
            setattr(instance, attr, val)

    if commit:
        instance.save()
它检查您试图更新的字段是否可编辑,是否不是主键,是否不是相关字段之一

用法示例:

book = Book.objects.first()
update_from_dict(book, {"num_pages":40, author:"Jack", date:"3324"})

奢侈的DRF序列化程序
.create
update
方法的缺点是字段集有限且经过验证,这不适用于手动更新。

如果您已经有Django对象,并且希望更新其字段,则可以不使用过滤器进行更新。因为你已经有了,在这种情况下,你可能会:

your_obj.__dict__.update(your_dict)
your_obj.save()

对试试看。在Python语言参考手册中查找
**
操作符。可能是复制品吧?你能举个例子吗?所以,我必须编写一个自定义函数,在字典中循环?@TIMEX:请阅读。非常清楚这是如何工作的。您能解释一下为什么使用
**
进行更新可能不是一个好主意吗?@Pocin使用
queryset.update(**字段)
是django docs认为的一个好主意。引用:“如果您只是更新一条记录,而不需要对模型对象执行任何操作,最有效的方法是调用update(),而不是将模型对象加载到内存中。”回答很好,调用非常明确。不喜欢过滤器(…)。更新(…),因为过滤器出错会导致大量覆盖。我认为更新只适用于查询集,而不适用于单个对象。请注意:
update()
不尊重信号。请看下面@leech的答案。这太棒了。嗯,更新和更新太糟糕了,或者创建不使用参数,只有save()使用。您的创建代码不会导致两次数据库命中吗?一个用于创建,另一个用于
.save()
?是,但不用于保存。如果已经创建了它,将有一个用于查找书籍(SELECT),然后另一个用于更新它(将生成update not INSERT语句)。如果该书不存在,则有一本可以查找(选择)并创建(插入)。
将不会发出任何信号。
:无法充分强调这一点。请添加“.”:您的目录更新(您的目录)
your_obj.__dict__.update(your_dict)
your_obj.save()