Фильтр исключения Django для нескольких внешних ключей одной и той же модели - PullRequest
0 голосов
/ 07 февраля 2019

Я пытаюсь отфильтровать набор запросов на основе вложенного содержимого в нескольких полях.Одно поле работает, а другое нет

Вот краткая версия моей модели:

class Shift(models.Model):
    users = models.ManyToManyField(User, blank=True)
    potential_users = models.ManyToManyField(User, blank=True, related_name='potential_users')

Я хочу отфильтровать ее так, чтобы пользователь НЕ был в пользователях, а НЕ в потенциальноматрибут пользователя.Я использую эту функцию исключения в наборе запросов:

queryset = Shift.objects.exclude(users__id__contains=self.request.user.id, potential_users__id__contains=self.request.user.id)

Я также пытался объединить в цепочку исключение:

queryset = Shift.objects.exclude(users__id__contains=self.request.user.id).exclude(potential_users__id__contains=self.request.user.id)

Когда пользователь находится в атрибуте пользователей смены, я не получаюлюбые сдвиги, которые ожидаются.НО, когда пользователь входит в атрибут потенциального пользователя, я получаю сдвиг.

У потенциальных пользователей

Когда пользователь находится в потенциальном пользователе.Я запускаю это в моем отладочном исполнителе после выполнения набора запросов:

self.request.user.id == queryset[0].potential_users.all()[0].id

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

Для пользователей

Когда я выполняю одинаковую фильтрацию с пользователем в атрибуте users, я получаюиндекс вне диапазона, который хорош, потому что это означает, что он не получил сдвиг.Что ожидается.Это проверка, которую я запускаю:

self.request.user.id == queryset[0].users.all()[0].id

Запрос

Это полный набор запросов:

Shift.objects.annotate(amount_users=Count('users')).filter(show_on_market=True, amount_users__lt=F('amount_of_employees'), start__week=self.request.query_params['week'], start__year=self.request.query_params['year'], start__gt=datetime.datetime.now()).exclude(users__id__contains=self.request.user.id, potential_users__id__contains=self.request.user.id)

Это запрос, который django выполняет

SELECT `shift_shift`.`id`, `shift_shift`.`title`, `shift_shift`.`start`, `shift_shift`.`end`, `shift_shift`.`amount_of_minutes`, `shift_shift`.`amount_of_employees`, `shift_shift`.`employment_agency_id`, `shift_shift`.`client_id`, `shift_shift`.`store_id`, `shift_shift`.`description`, `shift_shift`.`show_on_market`, `shift_shift`.`repeat_shift_id`, `shift_shift`.`is_repeat`, COUNT(`shift_shift_users`.`user_id`) AS `amount_users` FROM `shift_shift` LEFT OUTER JOIN `shift_shift_users` ON (`shift_shift`.`id` = `shift_shift_users`.`shift_id`) WHERE (`shift_shift`.`is_repeat` = False AND `shift_shift`.`show_on_market` = True AND `shift_shift`.`start` > 2019-02-11 14:54:28.462725 AND WEEK(`shift_shift`.`start`, 3) = 7 AND `shift_shift`.`start` BETWEEN 2019-01-01 00:00:00 AND 2019-12-31 23:59:59.999999 AND NOT (`shift_shift`.`id` IN (SELECT U1.`shift_id` FROM `shift_shift_users` U1 WHERE U1.`user_id` LIKE BINARY %df6c3f22-b3c2-40af-81c9-9a689083bd15%)) AND NOT (`shift_shift`.`id` IN (SELECT U1.`shift_id` FROM `shift_shift_potential_users` U1 WHERE U1.`user_id` LIKE BINARY %df6c3f22-b3c2-40af-81c9-9a689083bd15%))) GROUP BY `shift_shift`.`id`, `shift_shift`.`amount_of_employees` HAVING COUNT(`shift_shift_users`.`user_id`) < (`shift_shift`.`amount_of_employees`) ORDER BY `shift_shift`.`start` ASC

Кто-нибудь знает, что я делаю неправильно?

Ответы [ 3 ]

0 голосов
/ 07 февраля 2019

Простой ответ на вашу проблему:

from django.db.models import Q

user_id = self.request.user.id
queryset = Shift.objects.exclude(
    Q(users__id__contains=user_id) | Q(potential_users__id__contains=user_id
)
0 голосов
/ 07 февраля 2019

Попробуйте:

from django.db.models import Q
queryset = Shift.objects.exclude(Q(users__id__in=[self.request.user.id]) & Q(potential_users__id__in=[self.request.user.id]))
  • Используйте __contains только для проверки строк.Попробуйте синтаксис __in=[Array], чтобы проверить, существует ли элемент на множестве сторон.
  • С помощью Q () вы можете комбинировать несколько запросов (| = OR, & = AND)
  • Вы не должны связывать несколько filter () / exclude (), так как это менее эффективно для вычисления.
0 голосов
/ 07 февраля 2019

Если я правильно понимаю ваши намерения, а именно: not (in users) and not (in potential users), который можно изменить на: not (in users or in potential users), вы должны использовать исключение цепочка вместо одного вызова, то есть:

queryset = Shift.objects.exclude(
    users__id__contains=self.request.user.id,
).exclude(
    potential_users__id__contains=self.request.user.id
)
...