From 3eec9598815bda5b6a0e88499acf33cdab386e9f Mon Sep 17 00:00:00 2001 From: phzhik Date: Tue, 21 May 2024 01:05:55 +0400 Subject: [PATCH] * Cleanup & optimizations --- ...0018_alter_bonusprogramtransaction_user.py | 20 +++++++++++++ account/models/bonus.py | 2 +- store/admin.py | 2 +- store/models.py | 28 +++++++++++++------ store/views.py | 4 +-- 5 files changed, 42 insertions(+), 14 deletions(-) create mode 100644 account/migrations/0018_alter_bonusprogramtransaction_user.py diff --git a/account/migrations/0018_alter_bonusprogramtransaction_user.py b/account/migrations/0018_alter_bonusprogramtransaction_user.py new file mode 100644 index 0000000..576a147 --- /dev/null +++ b/account/migrations/0018_alter_bonusprogramtransaction_user.py @@ -0,0 +1,20 @@ +# Generated by Django 4.2.2 on 2024-05-20 21:01 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('account', '0017_alter_bonusprogramtransaction_type'), + ] + + operations = [ + migrations.AlterField( + model_name='bonusprogramtransaction', + name='user', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='bonus_transactions', to=settings.AUTH_USER_MODEL, verbose_name='Пользователь транзакции'), + ), + ] diff --git a/account/models/bonus.py b/account/models/bonus.py index b3a4c80..28d5f1b 100644 --- a/account/models/bonus.py +++ b/account/models/bonus.py @@ -78,7 +78,7 @@ class BonusProgramTransaction(models.Model): """ Represents the history of all bonus program transactions """ type = models.PositiveSmallIntegerField('Тип транзакции', choices=BonusType.CHOICES) - user = models.ForeignKey('User', verbose_name='Пользователь транзакции', on_delete=models.CASCADE) + user = models.ForeignKey('User', verbose_name='Пользователь транзакции', on_delete=models.CASCADE, related_name='bonus_transactions') date = models.DateTimeField('Дата транзакции', auto_now_add=True) amount = models.SmallIntegerField('Количество, руб') comment = models.CharField('Комментарий', max_length=200, null=True, blank=True) diff --git a/store/admin.py b/store/admin.py index 6d1be39..71ded69 100644 --- a/store/admin.py +++ b/store/admin.py @@ -29,7 +29,7 @@ class ChecklistAdmin(admin.ModelAdmin): return obj.status_updated_at or obj.created_at def get_queryset(self, request): - return Checklist.objects.with_base_related().annotate_price_rub().annotate_commission_rub() + return Checklist.objects.with_base_related() @admin.register(GlobalSettings) diff --git a/store/models.py b/store/models.py index f69c5c0..c2cb3a5 100644 --- a/store/models.py +++ b/store/models.py @@ -195,13 +195,26 @@ def generate_checklist_id(): class ChecklistQuerySet(models.QuerySet): def with_base_related(self): - return self.select_related('manager', 'category', 'payment_method', + return self.select_related('manager', 'category', 'category__parent', 'payment_method', 'promocode', 'price_snapshot', 'gift', 'customer') \ .prefetch_related(Prefetch('images', to_attr='_images')) + def annotate_bonus_used(self): + from account.models import BonusProgramTransaction, BonusType + + amount_subquery = Subquery( + BonusProgramTransaction.objects.all() + .filter(type=BonusType.SPENT_PURCHASE, + user_id=OuterRef('customer_id'), + order_id=OuterRef('id')) + .values('amount')) + + return self.annotate(_bonus_used=Coalesce(amount_subquery, 0)) + def default_ordering(self): return self.order_by(F('status_updated_at').desc(nulls_last=True)) + # TODO: deprecate def annotate_price_rub(self): return self.annotate( _yuan_rate=Case( @@ -211,6 +224,7 @@ class ChecklistQuerySet(models.QuerySet): _price_rub=Ceil(F('_yuan_rate') * F('price_yuan')) ) + # TODO: deprecate def annotate_commission_rub(self): default_commission = GlobalSettings.load().commission_rub over_150k_commission = F('_price_rub') * settings.COMMISSION_OVER_150K @@ -438,10 +452,6 @@ class Checklist(models.Model): @property def price_rub(self) -> int: - # Prefer annotated field for calculation - if hasattr(self, '_price_rub'): - return self._price_rub - # Get saved prices if self.price_snapshot_id: yuan_rate = self.price_snapshot.yuan_rate @@ -501,10 +511,6 @@ class Checklist(models.Model): @property def commission_rub(self) -> Decimal: - # Prefer annotated field - if hasattr(self, '_commission_rub'): - return self._commission_rub - # Prefer saved value if self.price_snapshot_id: return self.price_snapshot.commission_rub @@ -525,6 +531,10 @@ class Checklist(models.Model): @property def bonus_used(self): + # Prefer annotated field + if hasattr(self, '_bonus_used'): + return self._bonus_used + if self.customer_id is None: return 0 diff --git a/store/views.py b/store/views.py index caf8180..aa3e934 100644 --- a/store/views.py +++ b/store/views.py @@ -99,7 +99,7 @@ class ChecklistAPI(viewsets.ModelViewSet): def get_queryset(self): return Checklist.objects.all().with_base_related() \ - .annotate_price_rub().annotate_commission_rub() \ + .annotate_bonus_used() \ .default_ordering() def get_object(self): @@ -191,8 +191,6 @@ class StatisticsAPI(viewsets.GenericViewSet): # Prepare query to collect the stats qs = self.get_queryset() \ - .annotate_price_rub() \ - .annotate_commission_rub() \ .values('month') \ .annotate(total=Count('id'), total_completed=Count('id'),