Ven*_*tta 18 django django-models
我有一个非常基本的问题django.db.models
.
在这个官方的django教程中,如果你搜索单词" choice_set
",你会发现变量" choice_set
"没有在任何地方声明,但是神奇地说,我们可以在代码中开始使用它.
我想知道,这会django.db.models.Model
奇迹般地创建*_set变量,它创建了哪些其他变量?
Dav*_*son 29
您可以使用函数获取类的属性的完整列表,包括您定义的类和为其定义的属性dir
,只需执行此操作
dir(Poll)
Run Code Online (Sandbox Code Playgroud)
你会得到一些看起来有点像的东西(尽管不完全是 - 我是以迂回的方式构建它):
['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']
Run Code Online (Sandbox Code Playgroud)
这是很多价值观!我们可以看到类似的异常DoesNotExist
和MultipleObjectsReturned
,最重要的一个一起objects
.但Django没有添加其中一些属性.如果你这样做,dir(object())
你会在所有对象中找到属性列表:
['__class__', '__delattr__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']
Run Code Online (Sandbox Code Playgroud)
大多数情况下,你可以忽略以两个开头和结尾的那些__
.大多数其他人都是由Django添加的.
至于它实际设置的方式和位置:Django使用models.Model
元类动态设置每个新模型的大部分属性.首先要知道的是,您可以使用以下setattr
函数动态地向类添加成员或方法:
class X:
pass
setattr(X, "q", 12)
print X.q # prints 12
Run Code Online (Sandbox Code Playgroud)
这就是它如何根据您的属性名称创建新属性.
在本教程中,允许它开始定义这些额外属性的重要一行是:
class Poll(models.Model):
Run Code Online (Sandbox Code Playgroud)
这意味着Poll
该类继承了models.Model
该类(属于Django).继承有许多有用的属性 - 基本上,Poll
类继承了models.Model
类已设置的一些行为- 但它定义大多数这些新属性的位置在Model 元类中.元类是一个棘手的概念,但基本上它们可以作为创建新类的一个方法,并且通过定义一个,Django可以在models.py
定义元类时直接进入,并定义任何新类.
模型元类的代码可以在这里找到(从第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)
Run Code Online (Sandbox Code Playgroud)
在一个特殊情况之外'contribute_to_class
(对您的兴趣不重要),这是一种向类添加新属性(例如方法或成员)的方法.它被调用的地方给我们提示它添加的内容:
class.add_to_class('DoesNotExist', subclass_exception(str('DoesNotExist') ...<truncated>...
Run Code Online (Sandbox Code Playgroud)
这里是添加DoesNotExist
异常,如果你要求Poll
不存在则返回异常.(通过跑步Poll.objects.get(pk=1337)
或直接输入来查看Poll.DoesNotExist
).
但实际上Django比这更复杂.您要询问的特定 _set
属性不是为每个模型构建的 - 当一个字段与另一个字段相关时ForeignKey
(就像您Poll
和您的那样Choice
),它就会被创建.它被分配的各个地方非常复杂,但它基本上都返回到related.py中的这个get_accessor_name
函数
def get_accessor_name(self):
# This method encapsulates the logic that decides what name to give an
# accessor descriptor that retrieves related many-to-one or
# many-to-many objects. It uses the lower-cased object_name + "_set",
# but this can be overridden with the "related_name" option.
if self.field.rel.multiple:
# If this is a symmetrical m2m relation on self, there is no reverse accessor.
if getattr(self.field.rel, 'symmetrical', False) and self.model == self.parent_model:
return None
return self.field.rel.related_name or (self.opts.object_name.lower() + '_set')
else:
return self.field.rel.related_name or (self.opts.object_name.lower())
Run Code Online (Sandbox Code Playgroud)
这就是提出这个名字 - 追溯它以确定如何将它添加到课堂中并不是一件容易的事.但我希望你从中看到Django有很多机会添加这样的属性.
Dan*_*elB 11
这是一些ForeignKey
魔术:)
该Choice
模型具有属性poll
,这是一个ForeignKey
到一个Poll
对象.Django choice_set
为Poll
对象添加了方便方法,它将QuerySet
包含Choice
引用该Poll
Object的所有对象.
所以,给定这个(伪)代码
myPoll = Poll(question='Is Django awesome?')
option_yes = Choice(poll=myPoll, choice='Yes')
option_no = Choice(poll=myPoll, choice='No')
Run Code Online (Sandbox Code Playgroud)
你以后可以跑
poll = Poll.objects.get(question='Is Django awesome?')
options = poll.choice_set.all()
Run Code Online (Sandbox Code Playgroud)
和选项将包括相关的Choice
对象.
您可以related_name
在定义时使用该选项更改此属性的名称ForeignKey
.
归档时间: |
|
查看次数: |
7259 次 |
最近记录: |