Django orm MTM через ошибку фильтрации - PullRequest
1 голос
/ 10 июля 2020

У меня две модели:

class Training(models.Model):
    statuses = models.ManyToManyField('company.Company',
                                      through='TrainingStatus')

class TrainingStatus(models.Model):
    training = models.ForeignKey('Training', on_delete=models.CASCADE)
    company = models.ForeignKey('company.Company', on_delete=models.CASCADE)
    state = FSMField(default=TrainingStatusStates.NEW,
                     choices=TrainingStatusStates.choices)

Когда я делаю такой запрос:

trainings = Training.objects.filter(trainingstatus__state='new')
if not self.request.user.is_superuser:
   trainings = trainings.filter(trainingstatus__company__id=3016)

Я ожидал увидеть мою queryset фильтрующую тренировку от trainingstatus с состоянием new и company_id=3016

Что я вижу:

SELECT `user_management_training`.`id` FROM `user_management_training` 
INNER JOIN `user_management_trainingstatus` ON (`user_management_training`.`id` = `user_management_trainingstatus`.`training_id`) 
INNER JOIN `user_management_trainingstatus` T3 ON (`user_management_training`.`id` = T3.`training_id`) 
WHERE (`user_management_trainingstatus`.`state` = new AND T3.`company_id` = 3016)

Я получаю неверные результаты, потому что фильтрация применяется два раза ко всему набору запросов состояния обучения

Но если я изменю свой код на это:

trainings = Training.objects.filter(trainingstatus__state='new')
if not self.request.user.is_superuser:
   trainings = trainings.filter(trainingstatus__state='new',
                                trainingstatus__company=3016)

Он работает, как ожидалось.

Python 3,7 Django 1,11

1 Ответ

1 голос
/ 10 июля 2020

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

Нет . Если вы используете два разных .filter(…) s, то это независимые фильтры, поэтому СОЕДИНЕНИЯ выполняются по-разному.

Вы можете определить такое поведение с помощью Q объектов:

from django.db.models import Q

q = <b>Q(trainingstatus__state='new')</b>
if not self.request.user.is_superuser:
   q &= Q(trainingstatus__company__id=3016)
trainings = Training.objects.filter(q)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...