Я дам вам два подхода:
Выполнение этого с минимальным количеством запросов
Получите объекты Node
, а затем используйте их для полученияProject
объектов, а не наоборот:
nodes = Node.objects.filter(Q(project__project_collaborators=user) | Q(collaborators=user)).select_related('project').distinct()
Теперь у вас есть только нужные вам узлы и только те, которые вы хотите.У вас есть несколько представлений проекта.Если вам нужны только узлы, это не проблема.Если вам нужно составить список проектов, вы можете использовать Python для его компиляции достаточно легко, хотя и не как QuerySet
:
projects = []
for node in nodes:
if node.project not in projects:
projects.append(node.project)
Если вам нужны проекты как QuerySet
, вы можете получитьих с одним дополнительным запросом - вот код для этого (вместо блока выше):
project_ids = set([node.project.id for node in nodes])
projects = Project.objects.filter(id__in=project_ids)
Обратите внимание, что вам нужно будет повторно связать Project
экземпляры с их соответствующими Node
экземплярамиесли вам нужна эта ассоциация:
projects_and_nodes = {}
for project in projects:
projects_and_nodes[project] = [node for node in nodes if node.project == project]
Выполнение этого в максимально чистом коде
Кажется, вы уже знаете, как получить нужные вам экземпляры Project
- часть, которую вы не совсем поняли, получает правильные Node
экземпляров.Вам нужно немного логики, когда вы получите Project
, который говорит:
# pseudocode
if the user is a collaborator on this project:
get all the nodes
else:
get only the nodes applicable to the user
В этом сценарии используйте код, который вы предоставили, чтобы получить проекты, а затем вот Python для получения соответствующих узлов:
if request.user in project.project_collaborators.all():
nodes = project.node_set.all()
else:
nodes = project.node_set.filter(collaborators=request.user)
Надеюсь, это поможет.:)