Django 中的多对多查找

发布于 2024-08-02 10:29:38 字数 1771 浏览 4 评论 0原文

这可能非常简单,值得 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')

想象以下用户:

  • Alice 有 3 个文档,其中 1 个是 私人(意味着只有朋友可以看到 它)。她是鲍勃的朋友,是 无视马洛里,态度冷漠 朝向夏娃(意思是没有存储 关系)。
  • 马洛里有 2 份文件,均为公开文件 并且对每个人都冷漠。
  • Bob 有 1 个公开文档 并且还冷漠地对待 每个人。
  • 夏娃无视爱丽丝并且是 对 Mallory 和 Bob 漠不关心

搜索文档的用户应该产生以下结果:

  • Bob 搜索文档应该 参见 6,因为爱丽丝已使他成为朋友 他可以查看她的私人信息 文件。
  • 爱丽丝搜索文档应该 参见 4、鲍勃 1 和她的 3。她没有 请参阅 Mallory 的公开文件: 爱丽丝无视马洛里。
  • 马洛里搜索文件看到 5 - Alice 的公共的,她自己的 2 和鲍勃 1.爱丽丝忽视她没有 与马洛里所看到的有关,只是 爱丽丝没有看到马洛里的 文档。
  • 夏娃搜索文档看到 3 - 马洛里和鲍勃的公开文件为 她忽略了爱丽丝。

基本上,我正在努力找出返回上面描述的查询集的过滤器。有人有什么想法吗?

编辑

感谢费迪南德在下面的回答,我能够从他给我的开始中找到我想要的东西。 首先,我们想要获得一个与我加好友的人的列表,这是通过多对多关系进行反向查找:

friendly_authors = self.user.user_friends.all()

获取所有我忽略的人:

my_ignored = UserProfile.objects.get(user=self.user).ignored.all()

获取我可以查看的文档列表 - 可查看的文档,我的,或者是那些加我好友但我没有忽略的人写的:

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

This is probably insultingly simple and worthy of a Nelson Muntz laugh, but I'm having a real braindead moment tryng to make many to many connections across various model relationships.

I have the following models (simplified for your enjoyment!):

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')

Imaginging the following Users:

  • Alice has 3 documents, 1 of which is
    private (meaning only friends can see
    it). She is friends with Bob, is
    ignoring Mallory and is apathetic
    towards Eve (meaning no stored
    relationship).
  • Mallory has 2 documents, both public
    and is apathetic towards everyone.
  • Bob has 1 document which is public
    and is also apathetic towards
    everyone.
  • Eve is ignoring Alice and is
    apathetic to Mallory and Bob

Users searching for documents should produce the following:

  • Bob searching for documents should
    see 6, as Alice has made him a friend
    and he can view her private
    documents.
  • Alice searching for documents should
    see 4, Bobs 1 and her 3. She doesn't
    see Mallory's public documents as
    Alice is ignoring Mallory.
  • Mallory searching for documents sees
    5 - Alice's public ones, her own 2
    and Bobs 1. Alice ignoring her has no
    bearing on what Mallory can see, just
    that Alice doesn't see Mallory's
    docs.
  • Eve searching for documents sees 3 -
    Mallory and Bob's public documents as
    she has ignored Alice.

Basically, I'm having a mental struggle figuring out the filters to returning the querysets I described above. Anyone got any ideas?

EDIT

Thanks to Ferdinands answer below I was able to nut through to what I wanted with the start that he gave me.
First off, we want to get a list of people who have friended me which is a reverse lookup through the Many to Many relationship:

friendly_authors = self.user.user_friends.all()

Get all the people I've ignored:

my_ignored = UserProfile.objects.get(user=self.user).ignored.all()

Get a list of docs I can view - docs which are viewable, mine, or written by people who have friended me but whom I haven't ignored:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

心舞飞扬 2024-08-09 10:29:38

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

>>> 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)
...     )
... )

这会生成以下 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
        )
    )
)

It is a bit tricky, maybe you are looking for something like that:

>>> 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)
...     )
... )

This generates the following SQL (I did some formatting on the original output):

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
        )
    )
)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文