Как исключить экземпляры с пустыми наборами запросов в 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
только один раз, и один раз для предварительно найденного объекта.