为什么Django模型上这个错误输入的字段名称不会抛出异常?

时间:2017-05-22 14:47:45

标签: python django

我有一个名为Foo的模型。我可以创建此模型的新实例,并将其保存到数据库中,即使我指定了一个不存在的字段名称。例如:

foobar = Foo.objects.create()
foobar.abcdefg = True # The field abcdefg does not exist!
foobar.full_clean()
foobar.save()

为什么Django在分配给不存在的字段时不会抛出异常?我怎样才能让它抛出异常,至少在full_clean期间?

2 个答案:

答案 0 :(得分:1)

foobar只是一个类的实例。与任何实例一样,您可以随时添加属性:

>>> class Test(object):
...     myval = 7
... 
>>> t = Test()
>>> t.myval
7
>>> t.otherval = 'another'
>>> t.otherval
'another'

(正如Flimm在评论中指出的那样,您可以通过在班级中添加__slots__属性来防止这种情况发生)

您可以在self.__dict__方法中使用full_clean来检查无关属性,但您需要能够确定应该在哪些属性。请注意,模型实例具有_state属性,需要单独保留。

您可以使用此列表理解(来自this answer)获取模型上的字段名称列表:

[f.name for f in self._meta.get_fields()]

所以,然后迭代self.__dict__并在发现任何不在模型字段列表中并且不以下划线开头的键时引发异常。

答案 1 :(得分:1)

Python允许您在任何实例上虚拟地存储任何名称的属性。可以阻止这种情况(通过在C中编写类)。

它的工作原理是大多数实例将其属性存储在字典中。字典存储在名为 __ dict __ 的实例属性中。事实上,有些人说"类只是字典的语法糖。"也就是说,您可以使用带有字典的类来完成所有操作;课程只是让它变得更容易。

您已经习惯了静态语言,您必须在编译时定义所有属性。在Python中,类定义是执行的,而不是编译的;类就像任何其他类一样是对象;添加属性就像在字典中添加项一样简单。这是设计的。

实际上,事实上没有宣言这样的事情。也就是说,你永远不会声明"这个类有一个方法foo"或者"这个类的实例有一个属性栏",更不用说关于要存储在那里的对象类型的声明。您只需定义一个方法,属性,类等,并添加它。