13

これはおそらく非常に単純で、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 つのドキュメントを持っていますが、これは公開されており、誰に対しても無関心です。
  • イブはアリスを無視し、マロリーとボブに無関心です

ドキュメントを検索するユーザーは、次の情報を生成する必要があります。

  • ドキュメントを検索している Bob には 6 が表示されるはずです。これは、Alice が Bob を友人にしており、Bob は彼女のプライベート ドキュメントを表示できるためです。
  • Alice がドキュメントを検索すると、4、Bob 1、および彼女の 3 が表示されます。Alice は Mallory を無視しているため、Mallory の公開ドキュメントは表示されません。
  • ドキュメントを検索しているマロリーは、アリスの公開ドキュメント、彼女自身の 2、およびボブの 1 の 5 を参照します。
  • 文書を検索する Eve は、アリスを無視したため、マロリーとボブの公開文書を 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)
)
4

1 に答える 1

9

それは少しトリッキーです、多分あなたはそのような何かを探しています:

>>> 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
        )
    )
)
于 2009-08-23T12:07:47.110 に答える