Набор запросов только по первому внешнему ключу, связанному с экземпляром

Допустим, например, у меня есть такие модели:

class Person(models.Model):
    name = models.CharField(max_length=50, blank=True, null=True, verbose_name=_('name'))


class Keyword(models.Model):
    value = models.CharField(max_length=50, blank=True, null=True, verbose_name=_('name'))
    person = models.ForeignKey('Keyword', on_delete=models.CASCADE)

Я хотел бы сделать запрос по модели Person, где мы фильтруем ТОЛЬКО по первому ключевому слову, связанному с этим человеком.

Список ключевых слов всегда упорядочен.

Так, например:

У человека Джон Доу есть 3 ключевых слова (Программирование, Путешествия, Семья)

Я бы хотел сделать что-то вроде этого (если это возможно)

Person.objects.filter(keyword_"first"="Programming") 

You can annotate with .alias(…) [Django-doc] with a Subquery expression [Django-doc], and then filter:

from django.db.models import OuterRef, Subquery

class Person.objects.alias(
    first_keyword=Subquery(
        Keyword.objects.filter(
            person=OuterRef('pk')
        ).values('value')[:1]
    )
).filter(
    first_keyword='Programming'
)

But models are by default unordered: that means that each time a different keyword can be the first. Only if you have a column and an ordering option [Django-doc], or an .order_by(…) clause [Django-doc] in the subquery, it is guaranteed that a certain item will be the first keyword.

Вы можете сделать фильтрацию необязательной с помощью поля only_first, которое будет фильтровать по первому элементу, если True и по всем элементам, если False:

from django.db.models import OuterRef, Q, Subquery

class Person.objects.alias(
    first_keyword=Subquery(
        Keyword.objects.filter(
            person=OuterRef('pk')
        ).values('value')[:1]
    )
).filter(
    Q(first_keyword='Programming') |
    Q(only_first=False, keyword__value='Programming')
)
Вернуться на верх