如何在单独的模型中通过最新对应条目中的文本字段过滤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进行查询,但如果可能的话,我真的希望避免使用原始SQL。

此解决方案使用了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字段的好名称。

您可以通过查询DataThing同时引用DataThingHistory:来执行同样的操作

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

查看django文档,了解如何查询反向关系。

编辑:

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

from django.db.models import Max
search_results = search_results.values('field1', 'field2',...).annotate(latest_history=Max('datathinghistory__timestemp'))

这不会为您提供完整的DataThing对象,但您可以根据需要向values添加任意多的字段。

最新更新