【问题标题】:Sorting by Value of Object in Many to Many Field Django在多对多字段Django中按对象的值排序
【发布时间】:2020-09-05 17:37:32
【问题描述】:

对于涉及多对多关系的 django 查询集,我需要一些排序帮助。

我正在制作一个基于语言的对话应用程序,并且我刚刚完成了一个查询,该查询返回一个名为 possibleMatches 的查询集,其中包含某人可能想要与之聊天的用户。但是,现在我想按他们在user languages 表中的特定语言的level 对这些用户进行排序。我相信解决方案在于使用 Django 的 annotate() 函数对查询集进行排序,但我一直无法找到准确的语法来执行此操作。我也尝试过使用过滤关系,但是在运行它时,我得到一个错误,说过滤关系不支持嵌套条件。

每个用户都有一个id 和一个由多对多字段表示的user languages 列表。每种用户语言对应一种user、一种language和一种level。为清楚起见,这是我的模型:

class CustomUser(AbstractUser):

    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)

class Language(models.Model):

    id = models.IntegerField(primary_key=True, choices=SUPPORTED_LANGUAGES)

class UserLanguage(models.Model):

    language = models.ForeignKey(Language, on_delete=models.DO_NOTHING)
    user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='languages', on_delete=models.DO_NOTHING)
    level = models.IntegerField(choices=LANGUAGE_PROFICIENCIES, null=False, blank=False)

无论如何,我想根据语言1levelpossibleMatches 中的用户进行升序排序。这是我到目前为止的代码和查询:

sortingLanguage= Language.objects.get(id=1)
possibleMatches.annotate(language_1="languages__language__id=sortingLanguage.id").order_by(language_1.level)

但我不断收到语法错误,我不确定 filter()、annotate()、When() 和 Case() 的正确组合是什么才能使其正常工作(我想我是使语法与过滤多对多关系的语法混淆)。有谁知道正确的语法是什么?非常感谢您。

【问题讨论】:

  • languages__language__id=sortingLanguage.id 也没有多大意义。想象一下User 没有sortingLanguage 作为语言,你想把它从possibleMatches 中排除吗?
  • 他们将始终将sortingLanguage 作为一种语言,我根据我的过滤方式确保了这一点,以便获得possibleMatches。但我也可以使用一个简单地将没有排序语言的每个人放在列表底部的解决方案

标签: django django-queryset


【解决方案1】:

您可以先过滤多对多关系,只保留引用sortingLanguageUserLanguage,然后您可以对该语言的level进行排序:

CustomUser.objects.filter(
    languages__language=sortingLanguage
).order_by('languages__level')

如果排序语言的id已知,则不必先将该对象取到内存中,直接通过id过滤即可:

CustomUser.objects.filter(
    languages__language_id=1
).order_by('languages__level')

您可以使用聚合按最大的过滤级别排序:

如果排序语言的id已知,则不必先将该对象取到内存中,直接通过id过滤即可:

from django.db.models import Max

CustomUser.objects.filter(
    languages__language_id=1
).annotate(
    highest_level=Max('languages__level')
).order_by('highest_level')

【讨论】:

  • 谢谢,我没有意识到你可以用这种方式过滤多对多关系。但是,现在当我运行possibleMatches.filter(languages__language_id=sortingLanguage.id).order_by('languages__level') 时,我得到了一个重复的用户,即使我在末尾添加了.distinct()。你知道可能会发生什么吗?我会澄清并说我必须在排序之前在possibleMatches上调用distinct()以避免重复。
  • @Gomes: 同一个Language 可以为同一个用户出现多次次吗?
  • 不,用户的user language 列表中必须有不同的languages
  • @Gomes: 如果你使用.distinct() .order_by(...)之后呢?
  • 同样的结果,我还有一个重复
猜你喜欢
  • 2021-11-05
  • 1970-01-01
  • 2015-03-31
  • 1970-01-01
  • 2019-04-10
  • 1970-01-01
  • 1970-01-01
  • 2020-04-27
  • 1970-01-01
相关资源
最近更新 更多