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()
)

Оба варианта выглядят лучше, чем вложенный запрос.

Вернуться на верх