在 Django 中设置 GenericForeignKey 字段值
Setting GenericForeignKey field value in Django
我最近一直在阅读有关泛型关系的内容。我知道 GenericForeignKey
是使用 ForeignKey
和 PositiveIntegerField
字段定义和管理通用关系。我深入研究了源代码以搜索 GenericForeignKey
的 __set__
方法,看看它是如何工作的。
这是 GenericForeignKey.__set__()
的片段:
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)
和 django 文档中的模型定义 example:
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>
吗?
>>> guido = User.objects.get(username='Guido')
>>> t = TaggedItem(content_object=guido, tag='bdfl')
>>> t.save()
__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
的实例class(inst
),而
value
是您将属性设置为 ("foo"
)。
查看更详尽的示例 here。
因此,如果不同样深入研究 Django 代码,看起来:
self
是GenericForeignKey
描述符的实例(TaggedItem.content_object
),
instance
是TaggedItem
的实例class,而
value
是您要设置的属性。
但请注意,这一行:
t = TaggedItem(content_object=guido, tag='bdfl')
看起来您正在创建一个 TaggedItem
,它 创建 一个包含此行的描述符
content_object = GenericForeignKey('content_type', 'object_id')
因此,至少从您发布的代码来看,不会调用 __set__
方法。相反 GenericForeignKey
的 __init__
方法将被调用。
要调用 GenericForeignKey
的 __set__
方法,您需要有一个 class 实例(称之为 inst
),该实例具有 GenericForeignKey
描述符作为一个属性(称之为attr
),然后这样写:
inst.attr = "not guido"
然后,GenericForeignKey
描述符的__set__
方法将被调用。
我最近一直在阅读有关泛型关系的内容。我知道 GenericForeignKey
是使用 ForeignKey
和 PositiveIntegerField
字段定义和管理通用关系。我深入研究了源代码以搜索 GenericForeignKey
的 __set__
方法,看看它是如何工作的。
这是 GenericForeignKey.__set__()
的片段:
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)
和 django 文档中的模型定义 example:
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>
吗?
>>> guido = User.objects.get(username='Guido')
>>> t = TaggedItem(content_object=guido, tag='bdfl')
>>> t.save()
__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
的实例class(inst
),而value
是您将属性设置为 ("foo"
)。
查看更详尽的示例 here。
因此,如果不同样深入研究 Django 代码,看起来:
self
是GenericForeignKey
描述符的实例(TaggedItem.content_object
),instance
是TaggedItem
的实例class,而value
是您要设置的属性。
但请注意,这一行:
t = TaggedItem(content_object=guido, tag='bdfl')
看起来您正在创建一个 TaggedItem
,它 创建 一个包含此行的描述符
content_object = GenericForeignKey('content_type', 'object_id')
因此,至少从您发布的代码来看,不会调用 __set__
方法。相反 GenericForeignKey
的 __init__
方法将被调用。
要调用 GenericForeignKey
的 __set__
方法,您需要有一个 class 实例(称之为 inst
),该实例具有 GenericForeignKey
描述符作为一个属性(称之为attr
),然后这样写:
inst.attr = "not guido"
然后,GenericForeignKey
描述符的__set__
方法将被调用。