如何根据日期和时间将状态更新为过期或有效?

问题描述 投票:0回答:1

我有一个用 Django 构建的应用程序。该应用程序允许企业管理其日常运营,并具有以下功能:人力资源管理、销售、销售点、会计等

为了让企业能够在其产品上附加折扣,我创建了一个

Discount
模型:

class Discount(CommonField):
    name = models.CharField(max_length=255, blank=True, null=True)
    discount = models.DecimalField(max_digits=15, decimal_places=2)
    discount_type = models.CharField(max_length=255, choices=DISCOUNT_TYPE_CHOICES, blank=True, null=True)

    discounted_products_count = models.PositiveSmallIntegerField(default=0)

    start_date = models.DateTimeField(blank=True, null=True)
    expiry_date = models.DateTimeField(blank=True, null=True)

    status = models.CharField(max_length=255, default="inactive", choices=DISCOUNT_STATUS)

    objects = DiscountModelManager()

折扣具有已包含在模型中的开始日期到期日期,它们还有一个状态字段,用于确定状态是过期活动还是非活动

我面临的挑战之一是我应该在什么时候更新折扣状态。为了克服这一挑战,我创建了一个 Model Manager 来放置更新状态逻辑的中心位置;

class DiscountModelManager(TenantAwareManager):
    def get_queryset(self):
        queryset = super().get_queryset()
        self.change_promo_code_if_end_date_extended(queryset)
        self.activate_discount_if_start_date_reached(queryset)
        self.expire_discount_if_expiry_date_reached(queryset)
        return super().get_queryset()
        

    def change_promo_code_if_end_date_extended(self, queryset):
        """
        Activates promo codes if expiry_date has been extended and the status is expired.
        """
        queryset.filter(expiry_date__gte=timezone.now(), status="expired").update(status="active")

    def activate_discount_if_start_date_reached(self, queryset):
        """
        Activates promo codes if start_date has been reached and the status is inactive.
        """
        queryset.filter(start_date__lte=timezone.now(), status="inactive").update(status="active")

    def expire_discount_if_expiry_date_reached(self, queryset):
        queryset.filter(expiry_date__lte=timezone.now()).update(status="expired")

目前我对折扣有四种看法:

  1. Dicount List View
    :列出属于该特定业务的所有折扣(带分页)。
  2. Detail Discount View
    :显示折扣的详细视图。
  3. Edit Discount View
    :用户可以在详细视图中查看折扣后编辑折扣
  4. Point of Sale View
    :进行促销并且结帐时可以使用折扣的地方。

代码运行得非常好,除了我还有一个问题......

如果我们看一下折扣列表视图:

class DiscountListView(LoginRequiredMixin, View):
    def get(self, request):
        business_id = current_business_id()
        discounts = Discount.objects.filter(business__business_id=business_id)

        paginator = Paginator(discounts, 25)
        page_number = request.GET.get("page")
        page = paginator.get_page(page_number)

        context = {
            "table_headers": HTMLTemplateTags().table_headers["discounts"],
            "page": page,
            "search_query": search_query,
            "paginator": paginator,
        }

        return render(request, "pages/sales/discounts/discount_list.html", context)

您可以看到我们有一个

queryset
,我们正在其中获取属于当前业务的所有折扣

discounts = Discount.objects.filter(business__business_id=business_id)

在此查询集完成之前,会调用

DiscountModelManager
并更新状态。现在,这不是一个大问题,因为我们才刚刚开始,但是一旦我们的表中有数百万个折扣,那么这种方法根本就不是最佳的,因为属于特定业务的所有折扣都会更新。

有没有更好、更有效的方法来解决这个问题?

python django django-models optimization
1个回答
0
投票

我认为让该字段具有时间敏感性更好。只需在需要时确定状态即可,例如:

from django.db.models.functions import Now


class ActiveDiscountManager(models.Manager):
    def get_queryset(self, *args, **kwargs):
        return (
            super()
            .get_queryset(*args, **kwargs)
            .filter(start_date__gte=Now(), expiry_date__lte=Now())
        )


class Discount(CommonField):
    start_date = models.DateTimeField(blank=True, null=True, db_index=True)
    expiry_date = models.DateTimeField(blank=True, null=True, db_index=True)
    # no status field

    objects = models.Manager()
    active = ActiveDiscountManager()

    @property
    def status(self):
        if self.start_date is None or self.start_date < datetime.now():
            return 'inactive'
        elif self.end_date and self.end_date < datetime.now():
            return 'expired'
        else:
            return active

因此,我们不会更改状态或存储它,我们只是在需要时确定它。这也意味着,如果

end_date
延长或缩短,过滤将自动包含/排除
Discount
以及
Discount.active.all()
项目。

© www.soinside.com 2019 - 2024. All rights reserved.