CartController now uses BatchController memoisation
This commit is contained in:
		
							parent
							
								
									3717adb262
								
							
						
					
					
						commit
						3d635521eb
					
				
					 1 changed files with 13 additions and 56 deletions
				
			
		|  | @ -16,6 +16,7 @@ from registrasion.models import commerce | |||
| from registrasion.models import conditions | ||||
| from registrasion.models import inventory | ||||
| 
 | ||||
| from.batch import BatchController | ||||
| from .category import CategoryController | ||||
| from .discount import DiscountController | ||||
| from .flag import FlagController | ||||
|  | @ -34,10 +35,11 @@ def _modifies_cart(func): | |||
|     def inner(self, *a, **k): | ||||
|         self._fail_if_cart_is_not_active() | ||||
|         with transaction.atomic(): | ||||
|             with CartController.operations_batch(self.cart.user) as mark: | ||||
|                 mark.mark = True  # Marker that we've modified the cart | ||||
|             with BatchController.batch(self.cart.user): | ||||
|                 # Mark the version of self in the batch cache as modified | ||||
|                 memoised = self.for_user(self.cart.user) | ||||
|                 memoised._modified_by_batch = True | ||||
|                 return func(self, *a, **k) | ||||
| 
 | ||||
|     return inner | ||||
| 
 | ||||
| 
 | ||||
|  | @ -47,6 +49,7 @@ class CartController(object): | |||
|         self.cart = cart | ||||
| 
 | ||||
|     @classmethod | ||||
|     @BatchController.memoise | ||||
|     def for_user(cls, user): | ||||
|         ''' Returns the user's current cart, or creates a new cart | ||||
|         if there isn't one ready yet. ''' | ||||
|  | @ -64,59 +67,6 @@ class CartController(object): | |||
|             ) | ||||
|         return cls(existing) | ||||
| 
 | ||||
|     # Marks the carts that are currently in batches | ||||
|     _FOR_USER = {} | ||||
|     _BATCH_COUNT = collections.defaultdict(int) | ||||
|     _MODIFIED_CARTS = set() | ||||
| 
 | ||||
|     class _ModificationMarker(object): | ||||
|         pass | ||||
| 
 | ||||
|     @classmethod | ||||
|     @contextlib.contextmanager | ||||
|     def operations_batch(cls, user): | ||||
|         ''' Marks the boundary for a batch of operations on a user's cart. | ||||
| 
 | ||||
|         These markers can be nested. Only on exiting the outermost marker will | ||||
|         a batch be ended. | ||||
| 
 | ||||
|         When a batch is ended, discounts are recalculated, and the cart's | ||||
|         revision is increased. | ||||
|         ''' | ||||
| 
 | ||||
|         if user not in cls._FOR_USER: | ||||
|             _ctrl = cls.for_user(user) | ||||
|             cls._FOR_USER[user] = (_ctrl, _ctrl.cart.id) | ||||
| 
 | ||||
|         ctrl, _id = cls._FOR_USER[user] | ||||
| 
 | ||||
|         cls._BATCH_COUNT[_id] += 1 | ||||
|         try: | ||||
|             success = False | ||||
| 
 | ||||
|             marker = cls._ModificationMarker() | ||||
|             yield marker | ||||
| 
 | ||||
|             if hasattr(marker, "mark"): | ||||
|                 cls._MODIFIED_CARTS.add(_id) | ||||
| 
 | ||||
|             success = True | ||||
|         finally: | ||||
| 
 | ||||
|             cls._BATCH_COUNT[_id] -= 1 | ||||
| 
 | ||||
|             # Only end on the outermost batch marker, and only if | ||||
|             # it excited cleanly, and a modification occurred | ||||
|             modified = _id in cls._MODIFIED_CARTS | ||||
|             outermost = cls._BATCH_COUNT[_id] == 0 | ||||
|             if modified and outermost and success: | ||||
|                 ctrl._end_batch() | ||||
|                 cls._MODIFIED_CARTS.remove(_id) | ||||
| 
 | ||||
|             # Clear out the cache on the outermost operation | ||||
|             if outermost: | ||||
|                 del cls._FOR_USER[user] | ||||
| 
 | ||||
|     def _fail_if_cart_is_not_active(self): | ||||
|         self.cart.refresh_from_db() | ||||
|         if self.cart.status != commerce.Cart.STATUS_ACTIVE: | ||||
|  | @ -144,6 +94,13 @@ class CartController(object): | |||
|         self.cart.time_last_updated = timezone.now() | ||||
|         self.cart.reservation_duration = max(reservations) | ||||
| 
 | ||||
| 
 | ||||
|     def end_batch(self): | ||||
|         ''' Calls ``_end_batch`` if a modification has been performed in the | ||||
|         previous batch. ''' | ||||
|         if hasattr(self,'_modified_by_batch'): | ||||
|             self._end_batch() | ||||
| 
 | ||||
|     def _end_batch(self): | ||||
|         ''' Performs operations that occur occur at the end of a batch of | ||||
|         product changes/voucher applications etc. | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 Christopher Neugebauer
						Christopher Neugebauer