Выберите всю модель внешнего ключа django, если условие или часть, если другое условие - PullRequest
0 голосов
/ 02 декабря 2011

У меня есть следующие модели:

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 %}

Это позволяет мне распечатать все узлы, если пользователь является соавтором проекта, или только конкретные узлы, если они являются только соавтором узла, при этом распечатывая все проекты, с которыми они связаны.

1 Ответ

2 голосов
/ 03 декабря 2011

Я дам вам два подхода:

Выполнение этого с минимальным количеством запросов

Получите объекты 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)

Надеюсь, это поможет.:)

...