使用Django获取尽可能接近日期的不同条目的查询集

时间:2012-04-21 07:54:09

标签: python django django-models

所以,我有一个看起来像这样的模型:

class Names(models.Model):
  name = models.CharField()

class Entries(models.Model):
  name = models.ForeignKey(Names)
  date = models.DateField()

数据看起来像这样

name   |  date

name_1 |  2011-06-01
name_2 |  2011-03-01
name_3 |  2011-02-01
name_1 |  2010-06-01
name_2 |  2010-03-02
name_3 |  2010-02-01
name_4 |  2009-07-01

我想查询带有日期的条目,并获取每个名称记录一次,其中小于或等于到日期。所以,如果我使用日期 2011-06-01

进行查询,我希望这会返回
name_1 | 2011-06-01
name_2 | 2011-03-01
name_3 | 2011-02-01
name_4 | 2009-07-01

我的假设是这样可以解决问题:

date = datetime(year=2011, month=06, day=01)
results = Entries.objects.filter(date__lte=date).order_by('date').distinct('name')

但是,我一直在那里获得重复的名称条目。

任何提示,朋友?

编辑:解决方案由Gareth Rees提供。我不得不稍微修改它,但它看起来像这样:

sql = """myapp_entries.id = (SELECT E.id from myapp_entries AS E
                             WHERE E.name_id = myapp_names.id AND
                             '"""+date.strftime('%Y-%m-%d')+"""'
                             ORDER BY E.date DESC
                             LIMIT 1)'''

results = (Entries.objects
           .extra(where = [sql])
           .filter(date__lte = date)
           .order_by('name', 'date'))

3 个答案:

答案 0 :(得分:1)

以下是一些方法,具体取决于您需要的结果。

(1)如果您不介意以字典形式(而非Entries个对象)获取结果,则可以使用annotatevalues结合对结果进行分组。在这种情况下,您想要的查询将是这样的:

from django.db.models import Min
results = (Entries.objects
           .filter(date__lte = date)
           .values('name')
           .annotate(date = Min('date'))
           .order_by('name', 'date'))

(2)如果您需要将结果作为Entries个对象返回,那么您可以使用extra仅选择所有具有相同名称的条目中最早的条目:

sql = '''id = (SELECT E.id FROM myapp_entries AS E
                WHERE E.name_id = myapp_entries.name_id
                ORDER BY E.date
                LIMIT 1)'''
results = (Entries.objects
           .extra(where = [sql])
           .filter(date__lte = date)
           .order_by('name', 'date'))

答案 1 :(得分:0)

尝试使用.distinct('name__name'),因为您想要遍历外键。

答案 2 :(得分:0)

你可能应该阅读文档:https://docs.djangoproject.com/en/dev/ref/models/querysets/#distinct

.distinct(* fields)仅适用于postgres并要求您匹配.order_by和.distinct,例如:

results = Entries.objects.filter(date__lte=date).order_by('date').distinct('date')

所以在你的情况下,它很可能是这样的:

results = Entries.objects.filter(date__lte=date).order_by('name', 'date').distinct('name')