我有以下模型:
class Project(models.Model):
title = models.CharField(max_length=75)
description = models.CharField(max_length=250)
project_collaborators = models.ManyToManyField(User)
...
class Node(models.Model):
title = models.CharField(max_length=75)
collaborators = models.ManyToManyField(User)
project = models.ForeignKey(Project)
我想做的是选择用户是project_collaborator的所有项目,以及与该项目相关的所有节点,并选择用户是项目中某个节点上的合作者的所有项目,但在每个项目中只选择用户是合作者的节点。
用户可以是project_collaborator,也可以是节点上的合作者,但是这应该只返回项目/节点的一个实例。
到目前为止,我得到的最接近的是Project.objects.filter(Q(node__collaborators=user) | Q(project_collaborators=user)).distinct()
,但它不完全像我想的那样。
编辑:我使用的解决方案
我在views.py中开始这样做,以获得用户将与之关联的所有项目:
projects = Project.objects.select_related().filter(Q(project_collaborators=request.user) | Q(canvas__collaborators=request.user)).distinct()
然后在模板中我做了:
{% for project in projects %}
{{ project.title }}
<ul>
{% for node in project.node_set.all %}
{% if request.user in project.project_collaborators.all or request.user in node.collaborators.all %}
<li>{{ node.title }}</li>
{% endif %}
{% endfor %}
</ul>
<br />
{% endfor %}
如果用户是项目合作者,则可以打印出所有节点,如果用户只是节点合作者,则只能打印出特定节点,同时仍然打印出与之关联的所有项目。
我给你两种方法:
用尽可能少的查询完成
获取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)
希望有帮助。:)