* _set Django模型的属性

时间:2013-01-09 04:53:51

标签: django django-models

我有一个关于django.db.models的基本问题。

在此official django tutorial中,如果您搜索单词“choice_set”,您会看到变量“choice_set”未在任何地方声明,但神奇地说,我们可以开始在代码。

我想知道,django.db.models.Model做了什么,神奇地创建了* _set变量,以及它创建了哪些其他变量?

4 个答案:

答案 0 :(得分:29)

您可以使用dir函数获取类的属性的完整列表,包括您定义的类和为其定义的属性,只需执行

 dir(Poll)

你最终会得到一些看起来有点像的东西(虽然不完全是 - 我正以迂回的方式构建它):

['DoesNotExist', 'MultipleObjectsReturned', '__class__', '__delattr__',
'__dict__', '__doc__', '__eq__', '__format__', '__getattribute__', '__hash__',
'__init__', '__metaclass__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', 
'__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__unicode__',
 '__weakref__', '_base_manager', '_default_manager', '_deferred', '_get_FIELD_display', 
'_get_next_or_previous_by_FIELD', '_get_next_or_previous_in_order', '_get_pk_val', 
'_get_unique_checks', '_meta', '_perform_date_checks', '_perform_unique_checks', '_set_pk_val', 
'clean', 'clean_fields', 'curve_set', 'date_error_message', 'delete', 'full_clean', 'objects', 
'pk', 'prepare_database_save', 'save', 'save_base', 'choice_set',
'serializable_value', 'unique_error_message', 'validate_unique']

这是很多价值观!我们可以看到DoesNotExistMultipleObjectsReturned等异常,以及最重要的objects。但Django没有添加其中一些属性。如果您执行dir(object()),则会在所有对象中找到属性列表:

['__class__', '__delattr__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']

大多数情况下,您可以忽略以两个__开头和结尾的那些。其他大部分都是由Django添加的。


关于它实际设置的方式和位置:Django使用models.Model元类动态设置每个新模型的大部分属性。首先要知道的是,您可以使用setattr函数动态地向类添加成员或方法:

class X:
    pass
setattr(X, "q", 12)
print X.q  # prints 12

这就是它如何根据您的属性名称创建新属性。

在本教程中,允许它开始定义这些额外属性的重要一行是:

class Poll(models.Model):

这意味着Poll类继承了models.Model类(属于Django)。继承具有许多有用的属性 - 基本上,Poll类继承了models.Model类已设置的一些行为 - 但它定义大多数这些新属性的位置在模型{{3}中}。元类是一个棘手的概念,但基本上它们可以作为创建新类的一个方法,通过定义一个,Django可以在定义models.py元类时直接进入,并定义任何新类。

可以找到Model元类的代码metaclass(从第55行开始) - 它是一组代码,实际上是从头开始创建一个类。尽管看起来很复杂,但只要查看变量名称,就可以从中获得很多。例如,查看有希望命名的add_to_class方法:

def add_to_class(cls, name, value):
    if hasattr(value, 'contribute_to_class'):
        value.contribute_to_class(cls, name)
    else:
        setattr(cls, name, value)

'contribute_to_class的一个特殊情况之外(对您的兴趣不重要),这是一种向类添加新属性(例如方法或成员)的方法。它所在的地方给我们提示它添加了什么:

 class.add_to_class('DoesNotExist', subclass_exception(str('DoesNotExist') ...<truncated>...

这里添加了DoesNotExist异常,如果您要求Poll不存在,则返回该异常。 (通过运行Poll.objects.get(pk=1337)或直接输入Poll.DoesNotExist)查看自己。

但实际上Django比这复杂得多。您询问的特定 _set属性不是为每个模型构建的 - 当一个字段与另一个字段相关时,ForeignKey就会创建它(就像您的{{ 1}}和Poll)。它被分配的各个地方非常复杂,但它基本上都回到here

中的Choice函数
get_accessor_name

这只是提出了这个名字 - 追溯它以确定如何将它添加到课堂中并不是一件容易的事。但我希望你从中看到Django有很多机会添加这样的属性。

答案 1 :(得分:11)

这是一些ForeignKey魔术:)

Choice模型的属性为pollForeignKeyPoll个对象。 Django将方便方法choice_set添加到Poll个对象,这将提供包含引用QuerySet对象的所有Choice个对象的Poll

所以,给定这个(伪)代码

myPoll = Poll(question='Is Django awesome?')
option_yes = Choice(poll=myPoll, choice='Yes')
option_no = Choice(poll=myPoll, choice='No')

您可以稍后运行

poll = Poll.objects.get(question='Is Django awesome?')
options = poll.choice_set.all()

和选项将包含相关的Choice个对象。

您可以在定义related_name时使用ForeignKey选项更改此属性的名称。

答案 2 :(得分:1)

Choice有一个ForeignKey to Poll,Django自动生成便利方法Poll.choice_set()来访问引用该轮询的所有选项。

在Django文档中有一篇很好的文章介绍了以下关系的主题:

https://docs.djangoproject.com/en/1.11/topics/db/queries/#following-relationships-backward

答案 3 :(得分:0)

在您所指的文件中https://docs.djangoproject.com/en/1.2/intro/tutorial01/#intro-tutorial01

&#39; _set&#39;指的是与Poll对象相关的所有选项,因为Choice模型具有轮询,这是轮询ID的外键。

例如:

考虑民意调查表行(1,&#39;你好吗?&#39;,&#39; 2014 7 3&#39;)

和选择表

当你说

p = Poll.objects.get(id=1)

//现在p是一个保留&lt; 1的民意调查对象,&#39;你好吗?&#39;,&#39; 2014 7 3&#39;&gt;     p.choice_set.create(选择=&#34;第一&#34;,票= 8) //在Choice表中,它创建一个引用轮询ID 1的行,即选择表行(1,1,&#39; 1st&#39;,8)

基本上_set是指引用轮询表(ID)的Choice表(轮询)的元组