我最近一直在阅读有关通用关系的文章。我知道GenericForeignKey
是使用ForeignKey
和PositiveIntegerField
字段来定义和管理通用关系。我深入研究源代码,搜索__set__
的{{1}}方法,看看它是如何工作的。
以下是GenericForeignKey
的摘要:
GenericForeignKey.__set__()
来自django docs example的和模型定义:
def __set__(self, instance, value):
ct = None
fk = None
if value is not None:
ct = self.get_content_type(obj=value)
fk = value._get_pk_val()
setattr(instance, self.ct_field, ct)
setattr(instance, self.fk_field, fk)
setattr(instance, self.cache_attr, value)
当我将class TaggedItem(models.Model):
tag = models.SlugField()
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')
的值分配给guido
时,每个参数的值是多少:content_object
,self
和instance
value
?
是GenericForeignKey.__set__()
,self=<GenericForeignKey: 1>
还是instance='content_object'
?
value=<User: guido>
答案 0 :(得分:0)
__set__
方法适用于descriptors。
以下简单示例将显示传递给__set__
的参数是什么:
class MyDescriptor:
def __set__(self, instance, value):
print((self, instance, value))
class MyClass:
attr = MyDescriptor()
inst = MyClass()
inst.attr = "foo"
你会得到类似的东西:
<__main__.MyDescriptor object at 0x000002017192AD68>, # self
<__main__.MyClass object at 0x000002017192ACF8>, # instance
'foo' # value
具体做法是:
self
是MyDescriptor
描述符(MyClass.attr
)的实例,instance
是MyClass
类(inst
)的实例,value
是您将属性设置为("foo"
)的内容。查看更全面的示例here。
因此,如果没有类似地深入Django代码,它似乎是:
self
是GenericForeignKey
描述符(TaggedItem.content_object
)的实例,instance
是TaggedItem
类的实例,value
是您将属性设置为。但请注意,使用此行:
t = TaggedItem(content_object=guido, tag='bdfl')
您好像正在创建TaggedItem
,使用此行创建描述符
content_object = GenericForeignKey('content_type', 'object_id')
因此,至少从您发布的代码中,__set__
方法不会被调用。而是会调用GenericForeignKey
__init__
方法。
要调用GenericForeignKey
的{{1}}方法,您需要拥有一个具有{{的类的实例(称之为__set__
) 1}}描述符作为属性(称之为inst
),然后编写如下内容:
GenericForeignKey
然后,将调用attr
描述符的inst.attr = "not guido"
方法。