Django:使用真实对象设置通用(content_type)字段将其设置为None

时间:2009-06-01 15:32:22

标签: django django-models

更新3(首先阅读):

是的,这是由于对象“个人资料”尚未保存造成的。对于那些得到相同症状的人来说,道德是“如果在为其分配真实对象时,外来关键字段似乎设置为无,则可能是因为其他对象尚未保存。”

即使你100%确定它已保存,再次检查; - )


您好,

我在Django的类中使用content_type / generic外键。

创建类实例的行大致如下:

tag =  SecurityTag(name='name',agent=an_agent,resource=a_resource,interface=an_interface)

代理和资源都是content_type字段。

大多数情况下,这可以按照我的预期工作并创建适当的对象。但我有一个特定的情况,我称这行为创建一个SecurityTag,但代理字段的值似乎最终为无。

现在,在这种特殊情况下,我在前一行中测试an_agent的值确实包含代理类型的现有的,已保存的Django.model对象。确实如此。

然而,生成的SecurityTag记录在此字段中显示为None。

我对此感到非常困惑。我猜这个沿线的某个地方,ORM尝试在an_agent中提取对象的id失败了,但是没有引发错误消息或异常。我已经检查过an_agent对象已保存并且在其id字段中有一个值。

有人见过这样的东西吗?或者有什么想法?

====

更新:10天后,完全相同的错误在新环境中再次咬我:

这里有一些描述“安全标签”对象的代码,它基本上是

之间的映射

a)某种权限角色(在我们的系统中称为“代理”),这是一种通用的content_type,

b)资源,也是一个通用的content_type,(在当前的问题中给出了Pinax“Profile”),

和c)“接口”(基本上是一种访问类型......例如“可查看”或“可编辑”只是一个字符串)

class SecurityTag(models.Model) :
    name = models.CharField(max_length='50')
    agent_content_type = models.ForeignKey(ContentType,related_name='security_tag_agent')
    agent_object_id = models.PositiveIntegerField()
    agent = generic.GenericForeignKey('agent_content_type', 'agent_object_id')

    interface = models.CharField(max_length='50')

    resource_content_type = models.ForeignKey(ContentType,related_name='security_tag_resource')
    resource_object_id = models.PositiveIntegerField()
    resource = generic.GenericForeignKey('resource_content_type', 'resource_object_id')

在特定时刻之后,我这样做:

print "before %s, %s" % (self.resource,self.agent)
t = SecurityTag(name=self.tag_name,agent=self.agent,resource=self.resource,interface=self.interface_id)
print "after %s, %s, %s, %s" % (t.resource,t.resource_content_type,type(t.resource),t.resource_object_id)

之前的结果是,“资源”变量 引用了一个配置文件,但之后......

before phil, TgGroup object
after None, profile, <type 'NoneType'>, None

换句话说,虽然t.resource_content_type的值已设置为“profile”,但其他所有内容均为None。在我之前遇到这个问题时,我通过重新加载我试图分配给泛型类型的东西来“解决”它。我开始怀疑这是否是某种ORM缓存问题...变量“self.resource”是否包含某种代理对象而不是真实的东西?

一种可能性是配置文件尚未保存。但是,此代码被称为配置文件的after_save信号的结果。 (它正在设置默认权限),那么可能是未提交配置文件保存还是什么?

更新2:根据Matthew的建议,我添加了

print self.resource._get_pk_value() and self.resource.id

爆炸说Profile没有_get_pk_value()

2 个答案:

答案 0 :(得分:5)

所以这里是我注意到的通过Django代码:当你通过构造函数创建一个模型对象的新实例时,一个pre-init函数调用(通过信号)任何通用对象引用。

它不是直接存储您传入的对象,而是存储类型和主键。

如果你的对象是持久化的并且有一个ID,这样可以正常工作,因为当你以后获得该字段时,它会从数据库中检索它。

但是 - 如果您的对象没有ID,则获取代码不返回任何内容,并且getter返回None

您可以在django.contrib.contenttypes.generic.GenericForeignKeyinstance_pre_init函数中查看__get__中的代码。

答案 1 :(得分:1)

这并没有真正回答我的问题或满足我的好奇心,但是如果我在尝试在SecurityTag构造函数中使用它之前立即将an_agent对象从数据库中拉出来似乎确实有效。

之前我传递的是先前使用get_or_create制作的副本。这个旧实例是不是已经过时或范围了?