【发布时间】:2013-03-01 10:21:13
【问题描述】:
我们正在尝试使用prefetch_related 加速我们的应用程序。可以跟GenericForeignKey关系,也可以跟__关系更深,可惜如果相关模型没有这个字段就会失败。
这里是一些模型结构的例子
class ModelA(models.Model):
event_object = models.ForeignKey(SomeModelA)
class ModelB(models.Model):
event = models.ForeignKey(SomeModelB)
class ModelC(models.Model):
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey()
所以ModelC 实例可以指向ModelA 或ModelB。我可以使用这样的查询集来预取 A 和 B 模型:ModelC.objects.all().prefetch_related('content_object') 不幸的是,我还需要选择事件对象(SomeModelA 或 SomeModelB)
如果我尝试运行
ModelC.objects.all().prefetch_related('content_object', 'content_object__event_object')
如果我只有指向ModelA 的ModelC 实例,它会起作用,但在其他情况下,它会失败,因为ModelB 没有event_object 字段而是有event。
代码中的许多地方都使用了此模型,因此重命名字段不是一个好主意。所以我想知道是否有办法为字段/列创建别名。
我试图这样做:
class ModelB(models.Model):
event = models.ForeignKey(SomeModelB)
event_object = models.ForeignKey(SomeModelB, db_column='event_id', related_name='+')
使两个字段指向数据库表中的同一列。但是,这不起作用,因为它破坏了 save 方法。 Django 创建一个UPDATE SQL 查询,其中一列被放置两次并得到一个DatabaseError
有没有办法创建这样的别名?或者也许有另一种解决方案可以让prefetch_related 不抛出异常?
更新:在save方法中有一个update_fields参数可以用来排除这个字段。但是它是在 1.5 中引入的,我们使用的是 1.4。所以我继续寻找答案。
更新 #2:@shx2 要求我提供回溯。有 2 种可能的回溯。 第一个 - 当第一个对象上缺少属性时:
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/home/igor/workspace/projectname/eggs/Django-1.4.2-py2.7.egg/django/db/models/query.py", line 72, in __repr__
data = list(self[:REPR_OUTPUT_SIZE + 1])
File "/home/igor/workspace/projectname/eggs/Django-1.4.2-py2.7.egg/django/db/models/query.py", line 97, in __iter__
len(self)
File "/home/igor/workspace/projectname/eggs/Django-1.4.2-py2.7.egg/django/db/models/query.py", line 89, in __len__
self._prefetch_related_objects()
File "/home/igor/workspace/projectname/eggs/Django-1.4.2-py2.7.egg/django/db/models/query.py", line 570, in _prefetch_related_objects
prefetch_related_objects(self._result_cache, self._prefetch_related_lookups)
File "/home/igor/workspace/projectname/eggs/Django-1.4.2-py2.7.egg/django/db/models/query.py", line 1664, in prefetch_related_objects
(attr, first_obj.__class__.__name__, lookup))
AttributeError: Cannot find 'event_object' on ModelB object, 'content_object__event_object' is an invalid parameter to prefetch_related()
如果 prefetch_related 参数对第一个对象有效,那么我得到第二个回溯:
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/home/igor/workspace/projectname/eggs/Django-1.4.2-py2.7.egg/django/db/models/query.py", line 72, in __repr__
data = list(self[:REPR_OUTPUT_SIZE + 1])
File "/home/igor/workspace/projectname/eggs/Django-1.4.2-py2.7.egg/django/db/models/query.py", line 97, in __iter__
len(self)
File "/home/igor/workspace/projectname/eggs/Django-1.4.2-py2.7.egg/django/db/models/query.py", line 89, in __len__
self._prefetch_related_objects()
File "/home/igor/workspace/projectname/eggs/Django-1.4.2-py2.7.egg/django/db/models/query.py", line 570, in _prefetch_related_objects
prefetch_related_objects(self._result_cache, self._prefetch_related_lookups)
File "/home/igor/workspace/projectname/eggs/Django-1.4.2-py2.7.egg/django/db/models/query.py", line 1680, in prefetch_related_objects
obj_list, additional_prl = prefetch_one_level(obj_list, prefetcher, attr)
File "/home/igor/workspace/projectname/eggs/Django-1.4.2-py2.7.egg/django/db/models/query.py", line 1803, in prefetch_one_level
qs = getattr(obj, attname).all()
AttributeError: 'ModelB' object has no attribute 'event_object'
【问题讨论】:
-
可以添加
prefetch_related错误的traceback吗? -
为什么需要 ModelC 查询集?您不能只进行 2 个不同的查询并分别处理它们吗?我知道我的问题有点幼稚,但有时问题只是我们如何面对这些困难
-
@marianobianchi 不,我们尝试优化 django admin 的某些部分,因此我们需要一个查询集。上面的模型也被简化了,我们在实际项目中有更深的关系
标签: python django django-models django-database