我有一个模型,我需要几个特定字段的历史数据,因此我将这些字段放入具有外键关系的单独模型中。
有点像这样:
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进行查询,但我真的希望尽可能避免使用raw。
答案 0 :(得分:2)
此解决方案使用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
字段的好名称。
答案 1 :(得分:0)
您可以在引用DataThing
时查询DataThingHistory
来执行相同操作:
search_results = DataThing.objects.filter(datathinghistory__text_with_history__icontains=searchterm)
在how to query on reverse relationship上查看django doc。
修改强>
我之前的回答是不完整的。要搜索每个DataThing
的最新历史记录,您需要annotate
使用Max
时间戳:
from django.db.models import Max
search_results = search_results.values('field1', 'field2',...).annotate(latest_history=Max('datathinghistory__timestemp'))
这不会为您提供完整的DataThing
个对象,但您可以根据需要向values
添加任意数量的字段。