Как исключить экземпляры с пустыми наборами запросов в prefetch_related?
У меня есть две модели - Project и Contract.
Они имеют отношения "один ко многим".
class Contract(models.Model):
project = models.ForeignKey(Project)
Я получаю qs из Project экземпляров с соответствующим Contract экземпляром(ами).
projects = Project.objects.filter(active=True).prefetch_related(
Prefetch('contract_set', queryset=Contract.objects.filter(**filters), to_attr='contracts')
)
Но теперь мне нужно получить Project экземпляры с точным Contract экземпляром, поместив Contract guid в filters.
filters: Dict = {
'guid': some_guid,
}
Но я получаю все Project экземпляры, где только один имеет не пустой contracts attr, а остальные Project экземпляры имеют пустой contracts attr.
Я нашел такие вопросы:
Как исключить строки с пустым полем prefetch_related
Фильтр prefetch_related empty в django
но они мне не помогают
Я пробовал такие варианты:
a) используя OuterRef и Exist:
projects = Project.objects.filter(**filters_projects).annotate(
has_contracts=Exists(
Contract.objects.filter(project_id=OuterRef('pk'), **filters_contracts)
)
)
projects = projects.filter(has_contracts=True)
b) с помощью annotate:
projects = (
Project.objects.filter(**filters_projects)
.annotate(num_contracts=Count('contract'))
.exclude(num_contracts=0)
.prefetch_related(
Prefetch('contract_set', queryset=Contract.objects.filter(**filters_contracts), to_attr='contracts')
)
)
Они не работают на меня...
Как я могу реализовать требуемую функциональность?
Вам придется фильтровать как в Prefetch объекте , так и в объекте Project, поэтому:
projects = (
Project.objects.filter(
Exists(
Contract.objects.filter(
project_id=OuterRef('pk'), **filters_contracts
)
),
**filters_projects
)
.prefetch_related(
Prefetch(
'contract_set',
queryset=Contract.objects.filter(**filters_contracts),
to_attr='contracts',
)
)
.distinct()
)
Таким образом, вы используете **filters_contracts дважды: один раз, чтобы получить эти Project только один раз, и один раз для предварительно найденного объекта.