【问题标题】:Django ORM: Conditional filteringDjango ORM:条件过滤
【发布时间】:2016-04-22 23:01:35
【问题描述】:

在一个 Django 应用程序中,我在这样的模型中保留了每日用户分数:

class Score(models.Model):
    user = models.ForeignKey(User)
    score = models.PositiveIntegerField(default=0)
    date = models.DateField(auto_now_add=True)

我想找出用户分数与随后一天相比发生巨大变化的日子。也就是说,例如,如果用户得分比前一天高 10 倍。

如何在使用 Django ORM 的查询过滤器中包含这样的条件?是否可以使用此处所述的条件表达式进行单个查询:https://docs.djangoproject.com/en/1.9/ref/models/conditional-expressions/

谢谢。

【问题讨论】:

    标签: django django-queryset django-orm django-filters


    【解决方案1】:

    如果您稍微更改您的 Score 类以包含前一天的分数(这无疑是相当浪费的),您可以使用 F expressions 将查询打包成一行。

    你的新班级:

    class Score(models.Model):
    user = models.ForeignKey(User)
    score = models.PositiveIntegerField(default=0)
    lastscore = models.PositiveIntegerField(default=0)
    date = models.DateField(auto_now_add=True)
    

    那么过滤器就变成了:

    from django.db.models import F
    daily_chg = 10
    big_changes = Score.objects.filter(score__gt=daily_chg*F('lastscore'))
    

    我不会使用 timedeltas 来搜索和设置前一天的分数字段,而是 look into 通过 Meta 类建立排序并在保存当天的分数时调用 latest()

    【讨论】:

      【解决方案2】:

      使用timedelta,我们可以测试给定用户的上周天数:

      from my_app.models import Score
      import datetime
      
      def some_view(request):
          days_with_score_boost = []
          today = datetime.date.today()
          for each_day in xrange(0,7):
              day_to_test, day_before_to_test = today - datetime.timedelta(days=each_day), today - datetime.timedelta(days=each_day + 1)  
              day_before_score = Score.objects.get(user=request.user,date=today - datetime.timedelta(days=each_day)).score # will need to catch the exception raised if .get return None and process appropriately
              if Score.objects.filter(user=request.user,score__gte=days_before_score * 10,date=day_before_to_test).count() > 0:
                  days_with_score_boost.append(day_to_test)
      

      days_with_score_boost 将是一个 datetime.date 对象列表,其中分数比前一天增加了 10 或更多。

      针对您的评论,我会采取措施在保存时间检查分数提升是否发生。但是,我会摆脱 auto_now_add 以支持在 save 方法中编写。

      from django.utils import timezone
      from django.core.exceptions import ObjectDoesNotExist
      
      class Score(models.Model):
          user = models.ForeignKey(User)
          score = models.PositiveIntegerField(default=0)
          date = models.DateField(null=True,blank=True)
          increased_ten_over_previous_day = models.BooleanField(null=True,blank=True)
      
          def save(self, *args, **kwargs):
              self.date = timezone.now().today()
              try:
                  yesterday_score = Score.objects.get(date=self.date-timezone.timedelta(days=1)).score
                  self.increased_ten_over_previous_day = (yesterday_score * 10) <= self.score
              except ObjectDoesNotExist: # called if Score.object.get returns no object; requires you only have one score per user per date
                  self.increased_ten_over_previous_day = False
              super(self, Score).save(*args, **kwargs)
      

      然后您可以过滤 date_range 的对象,其中 increased_ten_over_previous_dayTrue

      【讨论】:

      • 感谢您的回答。但我想找出有提升的any user 以及何时,而不仅仅是request.user。我想知道这是否可以通过单个查询实现,可能使用CaseWhen 等条件表达式:docs.djangoproject.com/en/1.9/ref/models/…
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-10-01
      • 1970-01-01
      • 2016-05-26
      • 2018-11-12
      • 2011-04-17
      • 2021-09-13
      • 2018-11-18
      相关资源
      最近更新 更多