Django中的多对多查找

Ste*_*ike 12 django lookup many-to-many django-models relationship

这可能是侮辱性的简单而且值得Nelson Muntz笑,但我有一个真正的脑死亡时刻试图在不同的模型关系中建立多对多的联系.

我有以下型号(简化为您的享受!):

class Document(models.Model):
    title = models.CharField(max_length=200)
    author = models.ForeignKey(User, blank=True)
    content = models.TextField(blank=True)
    private = models.BooleanField(default=False)

class UserProfile(models.Model):
    user = models.ForeignKey(User, unique=True)
    friends = models.ManyToManyField(User, symmetrical=False, 
                                     related_name='user_friends')
    ignored = models.ManyToManyField(User, symmetrical=False, 
                                     related_name='user_ignored')
Run Code Online (Sandbox Code Playgroud)

成像以下用户:

  • Alice有3个文档,其中1个是私有的(意思是只有朋友可以看到它).她是鲍勃的朋友,忽略了马洛里,对夏娃漠不关心(意思是没有存储关系).
  • 马洛里有两份文件,都是公开的,对每个人都很冷漠.
  • 鲍勃有一份公开的文件,也对每个人都无动于衷.
  • 夏娃无视爱丽丝,对马洛里和鲍勃漠不关心

搜索文档的用户应该生成以下内容:

  • Bob搜索文件时应该看到6,因为Alice已经让他成为朋友并且他可以查看她的私人文件.
  • 爱丽丝搜索文件时应该看到4,Bobs 1和她3.她没有看到Mallory的公开文件,因为Alice忽略了Mallory.
  • Mallory搜索文件时看到5 - Alice的公共文件,她自己的2和Bobs 1.爱丽丝忽略她与Mallory可以看到的无关,只是Alice没有看到Mallory的文档.
  • Eve搜索文件时看到3 - Mallory和Bob的公开文件,因为她忽略了Alice.

基本上,我正在精神上努力找出过滤器以返回我上面描述的查询集.有人有任何想法吗?

编辑

感谢Ferdinands的回答,我能够通过他给我的开始坚持到我想要的东西.首先,我们希望得到一个与我结识的人员名单,这是通过多对多关系进行反向查询:

friendly_authors = self.user.user_friends.all()
Run Code Online (Sandbox Code Playgroud)

得到我忽略的所有人:

my_ignored = UserProfile.objects.get(user=self.user).ignored.all()
Run Code Online (Sandbox Code Playgroud)

获取我可以查看的文档列表 - 可以查看,使用或编写文档的文档,这些文档可能是我的朋友,但我没有忽略过:

docs = Document.objects.filter(
    (Q(viewable=True) | Q(author=self.user) | Q(author__in=friendly_authors))
     & ~Q(author__in=my_ignored)
)
Run Code Online (Sandbox Code Playgroud)

Fer*_*yer 8

这有点棘手,也许你正在寻找类似的东西:

>>> from django.db.models import Q
>>> me = User.objects.get(pk=1)
>>> my_friends = UserProfile.objects.get(user=me).friends.all()
>>> docs = Document.objects.filter(
...     Q(author=me) | (
...         Q(author__in=my_friends)
...         & ~Q(author__userprofile__ignored=me)
...     )
... )
Run Code Online (Sandbox Code Playgroud)

这会生成以下SQL(我在原始输出上做了一些格式化):

SELECT "myapp_document".*
FROM "myapp_document" WHERE (
    "myapp_document"."author_id" = %s
    OR (
        "myapp_document"."author_id" IN (
            SELECT U0."id" FROM "myapp_user" U0
            INNER JOIN "myapp_userprofile_friends" U1
                ON (U0."id" = U1."user_id")
            WHERE U1."userprofile_id" = %s
        )
        AND NOT (
            "myapp_document"."author_id" IN (
                SELECT U2."user_id" FROM "myapp_userprofile" U2
                INNER JOIN "myapp_userprofile_ignored" U3
                    ON (U2."id" = U3."userprofile_id")
                WHERE U3."user_id" = %s
            )
            AND "myapp_document"."author_id" IS NOT NULL
        )
    )
)
Run Code Online (Sandbox Code Playgroud)