浏览代码

Prevent unnecessary database query in UseFirstStockRecord strategy when passed an annotated product.

master
Samir Shah 3 年前
父节点
当前提交
a150206cd1
共有 2 个文件被更改,包括 17 次插入5 次删除
  1. 7
    5
      src/oscar/apps/partner/strategy.py
  2. 10
    0
      tests/integration/partner/test_selector_mixin.py

+ 7
- 5
src/oscar/apps/partner/strategy.py 查看文件

@@ -185,17 +185,19 @@ class Structured(Base):
185 185
 # Mixins - these can be used to construct the appropriate strategy class
186 186
 
187 187
 
188
-class UseFirstStockRecord(object):
188
+class UseFirstStockRecord:
189 189
     """
190 190
     Stockrecord selection mixin for use with the ``Structured`` base strategy.
191 191
     This mixin picks the first (normally only) stockrecord to fulfil a product.
192
-
193
-    This is backwards compatible with Oscar<0.6 where only one stockrecord per
194
-    product was permitted.
195 192
     """
196 193
 
197 194
     def select_stockrecord(self, product):
198
-        return product.stockrecords.first()
195
+        # We deliberately fetch by index here, to ensure that no additional database queries are made
196
+        # when stockrecords have already been prefetched in a queryset annotated using ProductQuerySet.base_queryset
197
+        try:
198
+            return product.stockrecords.all()[0]
199
+        except IndexError:
200
+            pass
199 201
 
200 202
 
201 203
 class StockRequired(object):

+ 10
- 0
tests/integration/partner/test_selector_mixin.py 查看文件

@@ -1,5 +1,6 @@
1 1
 from django.test import TestCase
2 2
 
3
+from oscar.apps.catalogue.models import Product
3 4
 from oscar.apps.partner import strategy
4 5
 from oscar.test import factories
5 6
 
@@ -17,3 +18,12 @@ class TestUseFirstStockRecordMixin(TestCase):
17 18
 
18 19
     def test_returns_none_when_no_stock_records(self):
19 20
         self.assertIsNone(self.mixin.select_stockrecord(self.product))
21
+
22
+    def test_does_not_generate_additional_query_when_passed_product_from_base_queryset(self):
23
+        product = Product.objects.base_queryset().first()
24
+        # Regression test for https://github.com/django-oscar/django-oscar/issues/3875
25
+        # If passed a product from a queryset annotated by base_queryset, then
26
+        # the selector should not trigger any additional database queries because
27
+        # it should rely on the prefetched stock records.
28
+        with self.assertNumQueries(0):
29
+            self.mixin.select_stockrecord(product)

正在加载...
取消
保存