0

我有两个类,它们之间是一对多的关系。

我有一个测试运行,导致父对象('fm')包含两个子对象,可通过相关管理器('changelog')访问。

以下代码运行,表明“更改日志”列表包含两个不同的UserMessageStatusUpdate对象,具有不同的属性:

>>> logging.debug(fm.changelog.all())
DEBUG [<UserMessageStatusUpdate: fred changed message status from New to Received>,
    <UserMessageStatusUpdate: fred changed message status from Received to Read>]

我也可以遍历它们:

>>> for m in fm.changelog.all():
    ....logging.debug(m)
DEBUG fred changed message status from New to Received
DEBUG fred changed message status from Received to Read

但是,如果我尝试通过索引访问每个对象,我会得到完全不同的东西:

>>> logging.debug(fm.changelog.all()[0])
DEBUG fred changed message status from Received to Read
>>> logging.debug(fm.changelog.all()[1])
DEBUG fred changed message status from Received to Read

这到底是怎么回事?

[更新 1]

我已将 ID 添加到模型 _str_() 方法中,所以现在我可以看到按索引访问方法两次返回相同的记录:

>>> logging.debug(fm.changelog.all()[0])
DEBUG id:3 fred changed message status from Received to Read
>>> logging.debug(fm.changelog.all()[1])
DEBUG id:3 fred changed message status from Received to Read

那么现在的问题是,为什么经理在通过索引访问时返回相同的记录?(这是默认的Manager,没什么特别的。)

[更新 2]

使用@stevejalim 对此进行调查,如果fm.changelog.all()对象显式地大小写为 a ,则测试将通过list

>>> changelog = list(fm.changelog.all())
>>> logging.debug(changelog[0])
DEBUG id:2 fred changed message status from New to Received
>>> logging.debug(changelog[1])
DEBUG id:3 fred changed message status from Received to Read

查看 fm.changelog.all():

>>> logging.debug(type(fm.changelog.all()))
DEBUG <class 'django.db.models.query.QuerySet'>

似乎问题可能与返回生成器的查询集有关,并且无法通过索引直接访问项目。或者可能与RelatedManager课堂上的这一行有关:https ://github.com/django/django/blob/stable/1.4.x/django/db/models/fields/related.py#L458

def get_query_set(self):
    try:
        return self.instance._prefetched_objects_cache[rel_field.related_query_name()]

基本上,这是一个谜,但投射到列表中就可以了。 1

4

1 回答 1

3

正如评论中所讨论的,解决方案是将返回的 QuerySet 转换为列表。我强烈怀疑这是底层 django 实现中的一个错误,因为在通过索引访问时返回错误元素是一种意外行为,但我无法准确找出问题所在。

默认行为给出错误(意外)结果:

>>> changelog = fm.changelog.all()
>>> changelog[0]
id:3 fred changed message status from Received to Read
>>> changelog[1]
id:3 fred changed message status from Received to Read

转换为列表会给出正确的(预期的)结果:

>>> changelog = list(fm.changelog.all())
>>> changelog[0]
id:2 fred changed message status from New to Received
>>> changelog[1]
id:3 fred changed message status from Received to Read
于 2012-12-04T14:45:02.913 回答