我在Django中完成了一个原始sql查询,并进行了测试以确保正在执行的查询数量减少到1.问题是我的迭代检查返回的对象会触发对该原始查询的重复调用。
class CategoryManager:
....
@staticmethod
def get_by_popularity():
return Category.objects.raw( """.........""" )
class CategoryManagerTestCase( TestCase ):
....
with self.assertNumQueries( 1 ):
categories = CategoryManager.get_by_popularity( )
for c in categories:
if c.name == root_cat.name:
self.assertEqual( c.visitors_count, 14 )
# when I add this second iteration the query gets executed a second time
for c in categories:
self.assertTrue( hasattr( c, 'id' ) )
self.assertTrue( hasattr( c, 'name' ) )
self.assertTrue( hasattr( c, 'parent_id' ) )
self.assertTrue( hasattr( c, 'description' ) )
self.assertTrue( hasattr( c, 'visitors_count' ) )
self.assertTrue( hasattr( c, 'projects_count' ) )
答案 0 :(得分:1)
不幸的是,原始查询是evaluated every time they are iterated
虽然RawQuerySet实例可以像普通法一样迭代 QuerySet,RawQuerySet不实现您可以使用的所有方法 查询集。例如,未定义 bool ()和 len () RawQuerySet,因此所有RawQuerySet实例都被认为是True。 这些方法没有在RawQuerySet中实现的原因是 在没有内部缓存的情况下实现它们将是一种表现 缺点和添加这样的缓存将是向后不兼容的。
答案 1 :(得分:1)
如果将结果转换为列表,则会阻止其他查询:
categories = list(CategoryManager.get_by_popularity())
或者您可能希望从您的方法返回一个列表:
@staticmethod
def get_by_popularity():
return list(Category.objects.raw( """.........""" ))
如果查询是Category.objects.filter(...)
而不是raw,那么多次循环遍历查询集只会导致它被提取一次。
然而,Django不会缓存原始查询集的结果。警告in the docs表明由于向后兼容性原因,未添加缓存。
虽然
RawQuerySet
实例可以像普通QuerySet
一样进行迭代,但RawQuerySet
并未实现您可以与QuerySet
一起使用的所有方法。例如,__bool__()
和__len__()
未在RawQuerySet
中定义,因此所有RawQuerySet
个实例都被视为True
。这些方法未在RawQuerySet
中实现的原因是,在没有内部缓存的情况下实现它们将是一个性能缺陷,并且添加此类缓存将是向后不兼容的。