Django复杂的过滤器和顺序

时间:2017-08-09 07:39:35

标签: sql django postgresql django-models django-queryset

我有4个这样的模型

sorted(Site.objects.all(), key=lambda x: x.get_lowest_price(the_date))

这里每个都有很多类别,每个类别都有很多产品。现在产品价格每天都在变化,因此价格模型将保持产品价格和日期。

我的问题是我想按价格范围列出网站过滤器。此价格范围取决于get_lowest_price方法,可以是Min to Max和Max to Min。我已经使用lambda表达式来做到这一点,但我认为它不合适

{{1}}

此外,我可以通过运行循环获得价格范围内的所有网站,但这也不是一个好主意。请帮助我的人以正确的方式进行查询。

如果您仍然需要更清楚地了解问题,请参阅" Ishtiaque Khan"的第一条评论,他的假设是100%正确的。

*在这些模型中,写入频率低且读取频率高。

3 个答案:

答案 0 :(得分:2)

<强> 1。使用查询
如果您只想使用特定日期查询。方法如下:

q = Site.objects.filter(category__product__price__date=mm_date) \
        .annotate(min_price=Min('category__product__price__price')) \
        .filter(min_price__gte=min_price, min_price__lte=max_price)

它将返回mm_date范围内价格最低的网站列表,其范围为min_price - max_price。您还可以使用如下查询查询多个日期:

q = Site.objects.values('name', 'category__product__price__date') \
        .annotate(min_price=Min('category__product__price__price')) \
        .filter(min_price__gte=min_price, min_price__lte=max_price)

<强> 2。急切/预先计算,您可以使用post_save信号。由于写入频率较低,因此不会很昂贵

  • 创建另一个以保持每个日期的最低价格。像这样:
    class LowestPrice(models.Model):
        date = models.DateField()
        site = models.ForeignKey(Site)
        lowest_price = models.IntegerField(default=0)
  • 每次使用post_save信号计算并更新此信息。示例代码(未测试)
    from django.db.models.signals import post_save
    from django.dispatch import receiver

    @receiver(post_save, sender=Price)
    def update_price(sender, instance, **kwargs):
        cur_price = LowestPrice.objects.filter(site=instance.product.category.site, date=instance.date).first()
        if not cur_price:
            new_price = LowestPrice()
            new_price.site = instance.product.category.site
            new_price.date = instance.date
        else:
            new_price = cur_price
        # update price only if needed
        if instance.price<new_price.lowest_price:
            new_price.lowest_price = instance.price
            new_price.save()
  • 然后在需要时直接从该表中查询:
    LowestPrice.objects.filter(date=mm_date, lowest_price__gte=min_price, lowest_price__lte=max_price)

答案 1 :(得分:0)

使用django queryset operations

执行此操作
Price.objects.all().order_by('price') #add [0] for only the first object

Price.objects.all().order_by('-price') #add [0] for only the first object

Price.objects.filter(date= ... ).order_by('price') #add [0] for only the first object

Price.objects.filter(date= ... ).order_by('-price') #add [0] for only the first object

Price.objects.filter(date= ... , price__gte=lower_limit, price__lte=upper_limit ).order_by('price') #add [0] for only the first object

Price.objects.filter(date= ... , price__gte=lower_limit, price__lte=upper_limit ).order_by('-price') #add [0] for only the first object

答案 2 :(得分:0)

我认为这个ORM查询可以完成这项工作......

from django.db.models import Min

sites = Site.objects.annotate(price_min= Min('category__product__price'))
            .filter(category__product__price=mm_date).unique().order_by('price_min')

或/和撤销订单:

sites = Site.objects.annotate(price_min= Min('category__product__price'))
            .filter(category__product__price=mm_date).unique().order_by('-price_min')