在Django中进行过滤时,如何保持项目顺序



我已经通过rating_predictionRecommendations进行了排序,并获得了ID,然后当我对其进行筛选以获得Tracks时,顺序不再相同

class RecommendationView(generics.ListAPIView):
authentication_classes = (TokenAuthentication,)
permission_classes = (IsAuthenticated,)
serializer_class = RecommendedTrackSerializer
queryset = Recommendations.objects.all()
pagination_class = api_settings.DEFAULT_PAGINATION_CLASS
def get_queryset(self):
recommendation = Recommendations.objects.filter(user=self.request.user)
sorted_recommendation = recommendation.order_by('-rating_prediction')
ids = list(sorted_recommendation.values_list('track', flat=True))
tracks = Track.objects.filter(id__in=ids)
return tracks

型号:

class Recommendations(models.Model):
user = models.ForeignKey(
User,
on_delete=models.CASCADE,
verbose_name='user which the recommendation is given',
)
track = models.ForeignKey(
Track,
on_delete=models.CASCADE,
verbose_name="track which recommend to the user",
)
date = models.DateField(
auto_now_add=True,
verbose_name='when the recommendation was generated',
)
rating_prediction = models.FloatField(
validators=[MinValueValidator(0), MaxValueValidator(5)]
)
class Track(models.Model):
track_id = models.CharField(max_length=24)
artist = models.ForeignKey(Artist, on_delete=models.CASCADE)
title = models.CharField(max_length=255)
link = models.URLField(max_length=255, blank=True)
tags = models.ManyToManyField(Tag, through='Tagged', blank=True)
similarity = models.ManyToManyField(
'self',
blank=True,
through='FusionSimilarity',
related_name='similar_to',
symmetrical=False
)
users = models.ManyToManyField(User, through='PlayTrack', blank=True)
Track.objects.filter(recommendation__user=self.request.user).order_by('-recommendation__rating_prediction')

我知道不久前有人问过这个问题,但如果您的排序列表无法通过queryset方法轻松访问,我想添加一个解决方案。

如果你的列表不太长,你可以建立一个条件列表来使用。像这样:

from typing import Any, List
from django.db.models import Case, When
def generate_sorting(ordered_list: List[Any], field_name: str) -> Case:
conditions_list = []
for index, field_value in enumerate(ordered_list):
condition = {field_name: field_value}
conditions_list.append(When(**condition, then=index))
return Case(*conditions_list, default=len(conditions_list))

ids = list(sorted_recommendation.values_list('track', flat=True))
id_sorting = generate_sorting(ids, "id")
"""
this will return something like this:
>>> generate_sorting([12, 3], "id")
id_sorting = Case(When("id"=12, then=0), When("id"=3, then=1), default=2)
"""
tracks = Track.objects.filter(id__in=ids).order_by(id_sorting)

您的过滤方式如下:

tracks = Track.objects.filter(id__in=ids)

但这并不意味着Trackids的顺序相同。您只需进行筛选,根据数据库对此进行索引的方式,它通常会根据id或其他指标生成列表顺序(例如,如果您将默认顺序附加到Track模型(。这也可能取决于数据库引擎。由于您从不声明订单,因此数据库可以"自由"选择任何订单。

然而,您可以减少查询量,并将其写成:

def get_queryset(self):
return Track.objects.filter(
recommendations__user=self.request.user
).order_by('-recommendations__rating_prediction')

如果用户每个曲目只能给出一个推荐,则不会产生任何重复。如果用户可以为一首曲目提供多个推荐,则应添加.distinct()调用。

因此,我们获得了给定用户推荐的Track,并根据用户推荐的方式对其进行排序,所有这些都在一个查询中。

最新更新