在Django中设置GenericForeignKey字段值

时间:2016-07-30 23:57:14

标签: python django django-contenttypes

我最近一直在阅读有关通用关系的文章。我知道GenericForeignKey是使用ForeignKeyPositiveIntegerField字段来定义和管理通用关系。我深入研究源代码,搜索__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_objectselfinstance value

GenericForeignKey.__set__()self=<GenericForeignKey: 1>还是instance='content_object'

value=<User: guido>

1 个答案:

答案 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

具体做法是:

  • selfMyDescriptor描述符(MyClass.attr)的实例,
  • instanceMyClass类(inst)的实例,
  • value是您将属性设置为("foo")的内容。

查看更全面的示例here

因此,如果没有类似地深入Django代码,它似乎是:

  • selfGenericForeignKey描述符(TaggedItem.content_object)的实例,
  • instanceTaggedItem类的实例,
  • 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" 方法