我有一个在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()

折扣有start dateexpiry date,这两个已包含在模型中,它们还有一个状态字段,用于确定状态是expiredactive还是inactive.

我面临的挑战之一与我应该在什么时候更新折扣状态有关.为了克服这一挑战,我创建了一个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:其中列出了属于该特定业务的所有折扣(101).
  2. Detail Discount View:其中显示折扣的详细视图.
  3. Edit Discount View:用户可以在详细信息视图中查看折扣后编辑折扣
  4. Point of Sale View:发生促销并且在 checkout 时可能使用折扣.

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

如果我们查看折扣列表查看:

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并更新状态.目前,这不是一个大问题,因为我们刚刚开始,但一旦我们有数百万个折扣,那么这种方法就根本不是最佳的,因为属于特定企业的所有折扣都会更新.

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

推荐答案

我认为最好是not个,以便使该领域具有时间敏感性.只需在需要时确定状态,例如:

from django.db.models import Q
from django.db.models.functions import Now


class ActiveDiscountManager(models.Manager):
    def get_queryset(self, *args, **kwargs):
        return (
            super()
            .get_queryset(*args, **kwargs)
            .filter(~Q(expiry_date__gte=Now()), start_date__gte=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被扩展或缩短,过滤将自动将DiscountDiscount.active.all()个项目一起再次包含/排除Discount.

因为我们添加了数据库索引,所以它通常会有效地检索Discount,但它也更强大,因为我们不需要主动更改状态.

Python相关问答推荐

如何使用关键参数按列对Pandas rame进行排序

在两极中实施频率编码

如果AST请求默认受csref保护,那么在Django中使用@ system_decorator(csref_protect)的目的是什么?

Python主进程和分支进程如何共享gc信息?

阅读Polars Python中管道的函数定义

强制venv在bin而不是收件箱文件夹中创建虚拟环境

跟踪我已从数组中 Select 的样本的最有效方法

三个给定的坐标可以是矩形的点吗

具有多个选项的计数_匹配

试图找到Python方法来部分填充numpy数组

如何使用LangChain和AzureOpenAI在Python中解决AttribeHelp和BadPressMessage错误?

如何过滤包含2个指定子字符串的收件箱列名?

OR—Tools CP SAT条件约束

如何从pandas的rame类继承并使用filepath实例化

在Django admin中自动完成相关字段筛选

与命令行相比,相同的Python代码在Companyter Notebook中运行速度慢20倍

为什么常规操作不以其就地对应操作为基础?

为什么t sns.barplot图例不显示所有值?'

如何使用Azure Function将xlsb转换为xlsx?

获取PANDA GROUP BY转换中的组的名称