简体   繁体   English

如何按DateTimeField排序并基于ForeignKey选择不同的元素?

[英]How can I sort by a DateTimeField and choose distinct elements based on a ForeignKey?

I am using PostgreSQL as database for my Django project. 我正在使用PostgreSQL作为Django项目的数据库。 I have the following models: 我有以下型号:

class Food(models.Model):
    """Stores a food entry"""
    name = models.CharField(max_length=50)
    image_id = models.CharField(max_length=20)
    description = models.TextField()

class SurveyResult(models.Model):
    """Stores survey food result based on emoji and personality"""
    emoji = models.CharField(max_length=10)
    personality = models.CharField(max_length=50)
    food = models.ForeignKey(Food, on_delete=models.CASCADE)
    timestamp = models.DateTimeField(auto_now_add=True)
    rating = models.PositiveSmallIntegerField(default=0)

I need to write a query sorted by '-timestamp' , and just get distinct values for 'food' . 我需要编写一个按'-timestamp'排序的查询,并且只获取'food'不同值。 This is my what I have tried: 这是我尝试过的:

SurveyResult.objects.order_by('-timestamp').distinct('food')

However, I am getting the following error: 但是,我收到以下错误:

ProgrammingError: SELECT DISTINCT ON expressions must match initial ORDER BY expressions LINE 1: SELECT DISTINCT ON ("recommender_surveyresult"."food_id") "r... ProgrammingError:SELECT DISTINCT ON表达式必须与初始ORDER BY表达式匹配第1行:SELECT DISTINCT ON(“ recommender_surveyresult”。“ food_id”)“ r ...

I have read several answers from several questions, and I found an answer that basically says to do something like this: 我已经从几个问题中读到了几个答案,并且发现了一个基本上说要这样做的答案:

SurveyResult.objects.order_by('food', '-timestamp').distinct('food')

However, I am not getting what I want that is the latest SurveyResult objects that have a distinct food . 但是,我没有得到我想要的是具有独特food的最新SurveyResult对象。

How can I achieve this? 我该如何实现?

Let's suppose I have the following table in my database: 假设我的数据库中有下表:

# surveyresults
id emoji personality food timestamp            rating
1  :)    Famous US     1  2018-01-01 - 9:00      1
2  XD    Famous CN     3  2018-01-01 - 9:10      2
3  :)    Famous NZ     5  2018-01-01 - 9:15      3
4  :(    Famous FR     5  2018-01-01 - 9:35      4
5  XD    Famous US     1  2018-01-01 - 9:45      5
6  ;)    Famous JP     4  2018-01-01 - 9:55      5
7  :o    Famous SP     4  2018-01-01 - 10:00     5

The query should give me the folowing: 该查询应给我以下内容:

id emoji personality food timestamp            rating
7  :o    Famous SP     4  2018-01-01 - 10:00     5
5  XD    Famous US     1  2018-01-01 - 9:45      5
4  :(    Famous FR     5  2018-01-01 - 9:35      4
2  XD    Famous CN     3  2018-01-01 - 9:10      2

I would also like to know if it is possible to achieve this just with one query. 我还想知道是否仅通过一个查询就可以实现这一目标。

You can achieve this using subquery as below, 您可以使用以下subquery来实现此目的,

SurveyResult.objects.filter(
    id__in=SurveyResult.objects.order_by('food', '-timestamp').distinct('food')
).order_by('-timestamp')

Explanation: 说明:

So basically subquery involve evaluation of more than one query , in your case, we are evaluating two queries. 所以基本上subquery涉及一个以上的评价query ,你的情况,我们正在评估两个查询。 The SQL for the above queryset would look like, 对于上面的SQL queryset会是什么样子,

SELECT "id", "emoji", "personality", "food", "timestamp", "rating"
FROM "appname_surveyresult"
WHERE id IN (
    SELECT "id", DISTINCT ON ("food") 
    FROM "appname_surveyresult"
    ORDER BY "food" ASC, "timestamp" DESC 
)
ORDER BY "timestamp" DESC

So firstly the inner (just like mathematics) query evaluates whose result becomes the input to the outer query resulting in the latest of latest among the distinct . 因此,首先,内部查询(就像数学一样)会评估其结果成为外部查询的输入,从而导致不同查询中的最新查询。 Read this for more. 阅读更多。

You might consider adding a meta class to your SurveyResults model and then specify your order there 您可以考虑将一个元类添加到SurveyResults模型中,然后在此处指定您的订单

class SurveyResult(models.Model):
    ...

   class Meta:
        ordering = ('-timestamp',)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM