Browse Source

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

master
Samir Shah 3 years ago
parent
commit
a150206cd1

+ 7
- 5
src/oscar/apps/partner/strategy.py View File

185
 # Mixins - these can be used to construct the appropriate strategy class
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
     Stockrecord selection mixin for use with the ``Structured`` base strategy.
190
     Stockrecord selection mixin for use with the ``Structured`` base strategy.
191
     This mixin picks the first (normally only) stockrecord to fulfil a product.
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
     def select_stockrecord(self, product):
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
 class StockRequired(object):
203
 class StockRequired(object):

+ 10
- 0
tests/integration/partner/test_selector_mixin.py View File

1
 from django.test import TestCase
1
 from django.test import TestCase
2
 
2
 
3
+from oscar.apps.catalogue.models import Product
3
 from oscar.apps.partner import strategy
4
 from oscar.apps.partner import strategy
4
 from oscar.test import factories
5
 from oscar.test import factories
5
 
6
 
17
 
18
 
18
     def test_returns_none_when_no_stock_records(self):
19
     def test_returns_none_when_no_stock_records(self):
19
         self.assertIsNone(self.mixin.select_stockrecord(self.product))
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)

Loading…
Cancel
Save