From 686a31b96a2b5bba4b9630940f0dc64343bd3610 Mon Sep 17 00:00:00 2001 From: xmeunier Date: Thu, 31 Oct 2024 22:35:52 +0100 Subject: [PATCH] Make aggregated values computed when called instead of stored in DB - GroupedOrder.total_price - Order.articles_nb - Order.price - Item.ordered_nb --- docs/development/architecture.md | 5 ++- ...emove_groupedorder_total_price_and_more.py | 36 +++++++++++++++++++ la_chariotte/order/models.py | 33 +++++++---------- la_chariotte/order/views/grouped_order.py | 13 +++---- la_chariotte/order/views/order.py | 4 --- .../tests/test_order_views_grouped_order.py | 4 +-- la_chariotte/tests/utils.py | 7 ---- 7 files changed, 57 insertions(+), 45 deletions(-) create mode 100644 la_chariotte/order/migrations/0027_remove_groupedorder_total_price_and_more.py diff --git a/docs/development/architecture.md b/docs/development/architecture.md index ff468c7..1edcef3 100644 --- a/docs/development/architecture.md +++ b/docs/development/architecture.md @@ -22,22 +22,21 @@ classDiagram name deadline : DateTime delivery_date : Date + delivery_slot place description orga : CustomUser - total_price } class Item{ name grouped_order : GroupedOrder ordered_nb - total_price + price max_limit } class Order{ grouped_order : GroupedOrder author : OrderAuthor - price created_date note } diff --git a/la_chariotte/order/migrations/0027_remove_groupedorder_total_price_and_more.py b/la_chariotte/order/migrations/0027_remove_groupedorder_total_price_and_more.py new file mode 100644 index 0000000..695a7c4 --- /dev/null +++ b/la_chariotte/order/migrations/0027_remove_groupedorder_total_price_and_more.py @@ -0,0 +1,36 @@ +# Generated by Django 4.2.16 on 2024-10-31 21:27 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("order", "0026_groupedorder_delivery_slot"), + ] + + operations = [ + migrations.RemoveField( + model_name="groupedorder", + name="total_price", + ), + migrations.RemoveField( + model_name="item", + name="ordered_nb", + ), + migrations.RemoveField( + model_name="order", + name="articles_nb", + ), + migrations.RemoveField( + model_name="order", + name="price", + ), + migrations.AlterField( + model_name="order", + name="created_date", + field=models.DateTimeField( + auto_now_add=True, verbose_name="Date et heure de commande" + ), + ), + ] diff --git a/la_chariotte/order/models.py b/la_chariotte/order/models.py index 55dd867..7dd7c0c 100644 --- a/la_chariotte/order/models.py +++ b/la_chariotte/order/models.py @@ -25,7 +25,6 @@ class GroupedOrder(models.Model): max_length=100, null=True, blank=True, verbose_name="Lieu de livraison" ) description = models.TextField("Description", null=True, blank=True) - total_price = models.DecimalField(max_digits=10, decimal_places=2, default=0) code = models.CharField(auto_created=True) def create_code_from_pk(self): @@ -52,16 +51,12 @@ class GroupedOrder(models.Model): ) self.code = f"{base_36_pk}{random_string}"[:code_length] - def compute_total_price(self): + @property + def total_price(self): price = 0 for order in self.order_set.all(): price += order.price - self.total_price = price - self.save() - - def compute_items_ordered_nb(self): - for item in self.item_set.all(): - item.compute_ordered_nb() + return price def get_total_ordered_items(self): total_nb = 0 @@ -123,26 +118,24 @@ class Order(models.Model): GroupedOrder, on_delete=models.CASCADE, related_name="order_set" ) author = models.ForeignKey(OrderAuthor, on_delete=models.CASCADE) - articles_nb = models.PositiveIntegerField(default=0) - price = models.DecimalField(max_digits=10, decimal_places=2, default=0) created_date = models.DateTimeField("Date et heure de commande", auto_now_add=True) note = models.TextField(max_length=200, null=True, blank=True) - def compute_order_articles_nb(self): + @property + def articles_nb(self): """Computes the number of articles in this order""" articles_nb = 0 for ord_item in self.ordered_items.all(): articles_nb += ord_item.nb - self.articles_nb = articles_nb - self.save() + return articles_nb - def compute_order_price(self): + @property + def price(self): """Computes the total price of the order""" price = 0 for ord_item in self.ordered_items.all(): price += ord_item.get_price() - self.price = price - self.save() + return price def __str__(self): # pragma: no cover return ( @@ -157,15 +150,13 @@ class Item(models.Model): price = models.DecimalField(max_digits=10, decimal_places=2) max_limit = models.PositiveSmallIntegerField(null=True, blank=True) - ordered_nb = models.IntegerField(default=0) - - def compute_ordered_nb(self): + @property + def ordered_nb(self): """Computes the number of times this item has been ordered""" ordered_nb = 0 for order in self.orders.all(): ordered_nb += order.nb - self.ordered_nb = ordered_nb - self.save() + return ordered_nb def get_total_price(self): """Returns the total price of all orders on this item""" diff --git a/la_chariotte/order/views/grouped_order.py b/la_chariotte/order/views/grouped_order.py index cea3ab8..b225d40 100644 --- a/la_chariotte/order/views/grouped_order.py +++ b/la_chariotte/order/views/grouped_order.py @@ -150,12 +150,6 @@ class GroupedOrderOverview(UserIsOrgaMixin, generic.DetailView): # Staff can see but not edit grouped orders return super().test_func() or self.request.user.is_staff - def get(self, request, *args, **kwargs): - # Compute grouped order total price before display - self.get_object().compute_total_price() - self.get_object().compute_items_ordered_nb() - return super().get(self, request, *args, **kwargs) - def get_context_data(self, **kwargs): context = super(GroupedOrderOverview, self).get_context_data(**kwargs) # Add share link to context @@ -228,7 +222,6 @@ class GroupedOrderDuplicateView(UserIsOrgaMixin, generic.RedirectView): # duplicate each item and add it to new_grouped_order for item in initial_grouped_order.item_set.all(): item.pk = None - item.ordered_nb = 0 item.save() new_grouped_order.item_set.add(item) @@ -300,7 +293,11 @@ class GroupedOrderExportView(UserIsOrgaMixin, generic.DetailView): context = super(GroupedOrderExportView, self).get_context_data(**kwargs) grouped_order = self.get_object() - items = grouped_order.item_set.filter(ordered_nb__gt=0).order_by("name") + items = [ + item + for item in grouped_order.item_set.all().order_by("name") + if item.ordered_nb > 0 + ] orders = grouped_order.order_set.all().order_by( "author__last_name", "author__first_name" ) diff --git a/la_chariotte/order/views/order.py b/la_chariotte/order/views/order.py index 4a02b90..032b219 100644 --- a/la_chariotte/order/views/order.py +++ b/la_chariotte/order/views/order.py @@ -72,7 +72,6 @@ def place_order(request, code): if error_message: order.delete() author.delete() - grouped_order.compute_items_ordered_nb() return render( request, "order/grouped_order_detail.html", @@ -103,8 +102,6 @@ def place_order(request, code): ) # Send confirmation mail and redirect to confirmation page - order.compute_order_price() - grouped_order.compute_items_ordered_nb() send_order_confirmation_mail(order) # Redirect to prevent data from being posted twice when the user hits the Back @@ -123,7 +120,6 @@ def validate_item_ordered_nb(item, ordered_nb): def validate_articles_ordered_nb(order): """Return an error if no items are ordered""" - order.compute_order_articles_nb() if order.articles_nb == 0: return "Veuillez commander au moins un produit" return None diff --git a/la_chariotte/tests/test_order_views_grouped_order.py b/la_chariotte/tests/test_order_views_grouped_order.py index cfce0c4..beb8744 100644 --- a/la_chariotte/tests/test_order_views_grouped_order.py +++ b/la_chariotte/tests/test_order_views_grouped_order.py @@ -1396,7 +1396,7 @@ class TestGroupedOrderSheetView: response = client_log.get(generate_sheet_url) assert response.status_code == 200 assert response.context["grouped_order"] == grouped_order - assert response.context["items"].count() == 0 + assert len(response.context["items"]) == 0 assert len(response.context["orders_dict"]) == 0 # we order some items in the grouped order @@ -1404,7 +1404,7 @@ class TestGroupedOrderSheetView: response = client_log.get(generate_sheet_url) assert response.status_code == 200 assert response.context["grouped_order"] == grouped_order - assert response.context["items"].count() == 2 + assert len(response.context["items"]) == 2 assert response.context["orders_dict"][order] == [3, 2] assert response.context["grouped_order"].total_price == 35 diff --git a/la_chariotte/tests/utils.py b/la_chariotte/tests/utils.py index b7cc913..d1b9e4e 100644 --- a/la_chariotte/tests/utils.py +++ b/la_chariotte/tests/utils.py @@ -44,11 +44,4 @@ def order_items_in_grouped_order(grouped_order): models.OrderedItem.objects.create(order=order, item=item_2, nb=2) models.OrderedItem.objects.create(order=order_2, item=item_1, nb=1) models.OrderedItem.objects.create(order=order_3, item=item_2, nb=1) - item_1.compute_ordered_nb() - item_2.compute_ordered_nb() - order.compute_order_price() - order_2.compute_order_price() - order_3.compute_order_price() - grouped_order.compute_total_price() - grouped_order.save() return order