Django ORM - порядок запросов по отфильтрованным отношениям внешнего ключа - PullRequest
1 голос
/ 11 июня 2019

Вопрос: Можно ли выполнить отфильтрованное левое соединение или объединение в подзапросе (очень простое в postgres) с помощью функций Django ORM / queryset?

Модели:

class User(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=256)

class DashboardItem(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=256)

class DashboardItemUserData(models.Model):
    id = models.AutoField(primary_key=True)
    user = models.ForeignKey(User)
    dashboard_item = models.ForeignKey(DashboardItem)
    is_favorite = BooleanField()

DashboardItemUserData хранит информацию для каждого пользователя о том, «одобрил» ли пользователь элемент панели мониторинга.Мне нужно иметь возможность сортировать DashboardItem на основе текущего запрашивающего пользователя.Однако мне нужно, чтобы объединение было отфильтровано, так как порядок должен уважать текущего пользователя, независимо от того, «одобрили» ли другие пользователи элемент или нет.

Запрос, который, я думаю, будет работать (или аналогично):

current_user = request.user
DashboardItem.objects.annotate(is_favorite=DashboardItemUserData.objects.filter(user=current_user).values('is_favorite')).order_by('is_favorite','name')

Вот что я бы сделал в SQL:

запрос postgres, используя where при объединении

запрос postgres, используя подзапрос

Ответы [ 2 ]

0 голосов
/ 12 июня 2019

Ненавижу отвечать на мой первый вопрос ... но оставлю это здесь на случай, если кто-нибудь еще столкнется с ним. Я нашел два подхода, которые будут работать здесь:

  1. Если мы можем гарантировать запись базы данных для каждого пользователя в таблице DashboardItemUserData, мы можем просто использовать «filter ()» для создания внутреннего соединения. Поскольку у пользователя будет запись для всех элементов DashboardItem, внутреннее объединение не исключит ни одной.
current_user = request.user
DashboardItem.objects.filter(dashboarditemuserdata__user=current_user).order_by('is_favorite', 'name')
  1. Если мы не можем гарантировать запись для каждого пользователя в DashboardItemUserData, мы можем использовать функцию FilteredRelation в Django ORM. Это создаст левое внешнее соединение, в котором мы сначала фильтруем таблицу DashboardItemUserData только для рассматриваемого пользователя (поэтому мы получаем правильные данные пользователя, но не разрушаем левое соединение).
current_user = request.user
DashboardItem.objects.annotate(user_item_data=FilteredRelation('dashboarditemuserdata', condition=Q(dashboarditemuserdata__user=current_user))).order_by('user_item_data__is_favorite', 'name')
0 голосов
/ 11 июня 2019
DashboardItemUserData.objects.filter(user_id=1).\
    annotate(name=dashboard_item__name).\
    order_by('is_favorite', 'name')

Подзапрос имел бы смысл, если бы это было ЛЕВОЕ соединение.Или если он содержит TOP / LIMIT.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...