Django выбирает запись, если ее отношение "многие-ко-многим" содержит данные
У меня есть 2 таблицы
class Job(models.Model):
name = models.CharField()
collaborators = models.ManyToManyField(User, through="Collaborator")
created_by = models.ForeignKey(User)
class Collaborator(models.Model):
job = models.ForeignKey(Job)
user = models.ForeignKey(User, related_name="jobs")
role = models.CharField()
Для пользователя я хочу выбрать все те Jobs
, где либо created_by=user
, либо пользователь находится в коллабораторах.
Следующий запрос не дает корректных результатов
Job.objects.filter(Q(created_by=user) | Q(collaborators=user))
Посмотрев на необработанный запрос, сгенерированный вышеприведенным кодом, я обнаружил, что это происходит потому, что запрос, созданный django ORM, создает LEFT OUTER JOIN
между Job
и Collaborator
, поэтому если есть несколько коллабораторов для одной и той же работы, он возвращает несколько строк одной и той же работы.
Что я придумал, так это следующий запрос
Job.objects.filter(Q(created_by=user) | Q(pk__in=user.jobs.all().values("job_id")))
Мой вопрос в том, есть ли лучший запрос, чем вышеупомянутый, который я могу использовать?
P.S. Я использую django 4.0
Вы можете использовать distinct() для удаления дубликатов из QuerySet, что кажется самым простым решением:
jobs = Job.objects.filter(Q(created_by=user) | Q(collaborators=user)).distinct()
Но можно также "group_by()" результаты, например:
jobs = (
Job.objects.filter(Q(collaborators=user) | Q(created_by=user))
.annotate(times_repeated=Count('id'))
.order_by()
)
Оба варианта выглядят лучше, чем вложенный запрос.