根据最新子记录的条件在Django中过滤模型

时间:2012-01-17 09:35:53

标签: python django django-queryset

我有两个这样的模型:

class Store(models.Model):
    name = models.CharField(max_length=255)

class Order(models.Model):
    store = models.ForeignKey(Store)
    date = models.DateTimeField(auto_now_add=True)
    success = models.BooleanField()

我想过滤最新订单成功的Store模型中的所有记录,即success == True

虽然看起来非常简单,但我在解决如何使用ORM查询系统完成此任务时遇到了问题。

有任何帮助吗?感谢。

4 个答案:

答案 0 :(得分:2)

我的方法是:做2个列表,第一个用(id_store,last_success_date)元组,第二个用(id_store,last_date)元组:

l_succ = stores.objects.filter( 
                       order__success = True 
                  ).annotate(
                       last_success=Max('order__date')
                  ).value_list (
                       'id', 'last_success'
                  )
#l_succ = [ (1, '1/1/2011'), (2, '31/12/2010'), ... ] <-l_succ result

l_last = stores.objects.annotate(
                       last_date=Max('order__date')
                  ).value_list (
                       'id', 'last_date'
                  )
#l_last = [ (1, '1/1/2011'), (2, '3/1/2011'), ... ]   <-l_last result

然后将商店ID用于最后数据和上次成功日期等于的商店,并且您有查询:

store_success_ids =  [ k[0] for k in l_succ if k in l_last ]
#store_success_ids = [1, 5, ... ]          <-store_success_ids result
#Cast l_last to dictionary to do lookups if you have a lot of stores.

result = Store.objects.filter( pk__in = store_success_ids)        

这似乎是一个优雅的解决方案,只有四行代码用于复杂的查询(但只需要简单的requeriment)。免责声明,未经测试。

答案 1 :(得分:1)

这只是一个想法,所以如果我完全错了,不要打败我:) 我以为你可以这样做:

# first annotate latest order to Store which returns new queryset, filter new qs
# by success = True
stores = Store.objects.annotate(Max('order__date')).filter(order__success=True)

老实说这是未经测试的。

答案 2 :(得分:0)

您可以在一个查询中执行此操作。

使用QuerySets的.extra()功能编写如下所示的SQL:

Store.objects.extra(where=['id in (select store_id from order where success = true)']) 

答案 3 :(得分:0)

这种方法对你有用吗?遍布所有商店并获取每个商店的最新成功(如果存在)。

我最初的想法是不正确的:

latest_successes = []
store_objects = Store.objects.all()
for store_obj in store_objects:
    try:
        latest_success = Order.objects.filter(store=store_obj).filter(success=True).order_by('-date')[0]
    except IndexError:
        pass
    else:
        latest_successes.append(latest_success)

根据@demalexx的实体评论进行编辑

latest_successes = []
store_objects = Store.objects.all()
for store_obj in store_objects:
    try:
        is_latest_success = store_obj.order_set.order_by('-date')[0].success
    except IndexError:
        pass
    else:
        latest_successes.append(store_obj)