2016-04-14 46 views
2

我有一个模型,我需要几个特定字段的历史数据,因此我将这些字段放入具有外键关系的单独模型中。有点像这个如何通过单独模型中最新相应条目中的文本字段筛选Django查询集

东西:

class DataThing(models.Model): 
    # a bunch of fields here... 


class DataThingHistory(models.Model): 
    datathing_id = models.ForeignKey('DataThing', on_delete=models.CASCADE) 
    text_with_history = models.CharField(max_length=500, null=True, blank=True) 
    # other similar fields... 
    timestamp = models.DateTimeField() 

现在我想要在后者的最新相应的条目使用文本字段来过滤前代车型。

基本上,如果这些人不是独立的模型我只是试试这个:

search_results = DataThing.objects.filter(text_with_history__icontains=searchterm) 

但我还没有想出一个好办法,碰到这个一个一对多的关系,做到这一点,只使用输入最新的时间戳,至少使用Django ORM。

我对如何使用原始SQL执行查询有一个想法,但我真的很想尽量避免使用原始数据。

回答

0

该解决方案利用了distinct(*fields)这是目前唯一的Postgres所支持:

latest_things = DataThingHistory.objects. 
    order_by('datathing_id_id', '-timestamp'). 
    distinct('datathing_id_id') 

lt_with_searchterm = DataThingHistory.objects. 
    filter(id__in=latest_things, text_with_history__icontains=searchterm) 

search_results = DataThing.objects.filter(datathinghistory__in=lt_with_searchterm) 

这将导致在单个数据库查询。为了提高可读性,我已经分解了查询,但是可以将其嵌套到单个语句中。顺便说一句,正如你可能在这里看到的,foo_id不是ForeignKey字段的好名字。

+0

感谢您的这一点,我只是尝试了这一点,它确实导致了一个查询。我将不得不做一些测试,看看它在实践中运行得如何,但这似乎现在解决了我的问题。 – jyap

0

你会通过查询DataThing参照DataThingHistory做同样的:

search_results = DataThing.objects.filter(datathinghistory__text_with_history__icontains=searchterm) 

检查Django的文档上how to query on reverse relationship

编辑:

我以前的答案是不完整的。为了搜索的最新历史记录每个DataThing,你需要annotate使用Max时间戳:

from django.db.models import Max 

search_results = search_results.values('field1', 'field2',...).annotate(latest_history=Max('datathinghistory__timestemp')) 

这不会给你完整的DataThing对象,但你可以为你想要的字段添加到values

+0

我该如何检查'DataThingHistory'对象与最新的'timestamp'?似乎只是做你描述的查询就会搜索所有相关的'DataThingHistory'条目。 – jyap

+0

对不起,我完全错过了你的要求。我编辑了我的答案,看看是否有道理。 –

相关问题