5

作業中のメッセージングモジュール用に、これら2つのクラスがあります。会話は参加者のグループ(2人以上)によって表されるという考え方です。私が見つけようとしている目的の会話には次の参加者がいるというロジックで会話を検索する方法を見つけるのに苦労しています。私は試しConversation.objects.filter(participants__in=[p1, p2])ましたが、これはORスタイルのクエリを実行します。p1は参加者であるか、p2は参加者です。p1とp2が欲しいのですが...pNは参加者です。何か助けはありますか?

class Conversation(models.Model):
    date_started = models.DateTimeField(auto_now_add=True)
    participants = models.ManyToManyField(User)

    def get_messages(self):
        return Message.objects.filter(conversation=self)

    def new_message(self, sender, body):
        Message.objects.create(sender=sender, body=body, conversation=self)
        self.save()


class Message(models.Model):
    sender = models.ForeignKey(User)
    body = models.TextField()
    date = models.DateTimeField(auto_now_add=True)
    conversation = models.ForeignKey(Conversation)

    def __unicodde__(self):
        return body + "-" + sender 
4

4 に答える 4

4

繰り返しフィルタリングする必要があると思います。私は少し睡眠不足なので、これはまったくナンセンスかもしれませんが、おそらく次のようなマネージャーの方法です:

class ConversationManager(models.Manager):
    def has_all(self, participants):
        # Start with all conversations
        reducedQs = self.get_query_set()
        for p in participants:
            # Reduce to conversations that have a participant "p" 
            reducedQs = reducedQs.filter(participants__id=p.id)
        return reducedQs

一般的に言えば、クラスメソッドではなく、テーブルレベルのクエリマネージャメソッドを作成する習慣を身に付ける必要があります。このようにすることで、必要に応じてさらにフィルタリングできるクエリセットが残ります。

ドキュメントにPaulというメンバー名を持つすべてのグループのクエリとこの回答に触発されました。

于 2012-12-02T07:33:58.440 に答える
2

同じ関連モデルでfilter()を複数回チェーンすると、生成されたクエリには同じテーブルへの追加のJOINが含まれます。

だからあなたは持っています:Conversation.objects.filter(participants=p1).filter(participants=p2)

生成されたクエリを確認することで、この動作を確認できますprint Conversation.objects.filter(participants=p1).filter(participants=p2).query

参照:https ://docs.djangoproject.com/en/dev/topics/db/queries/#spanning-multi-valued-relationships

それでもかなり単純で効率的であるため、クエリの後にPythonロジックを使用することは避けます。これには、データベースから大量のデータを取得し、繰り返して再度フィルタリングする必要があります。

于 2012-12-02T10:21:06.293 に答える
0

まず、関連する名前をparticipantsフィールドに追加します。

participants = models.ManyToManyField(User, related_name='conversations')

これは必須ではありませんが、より読みやすいIMOです。

次に、次のようなことを行うことができます。

p1.conversations.filter(participants__in=p2)

これにより、p2も参加しているすべてのp1の会話が返されます。

このフィルタリング方法のDB効率についてはよくわかりません。おそらく、他の種類のデータベース(Neo4jなどのグラフDB)を使用する方が適しています。

于 2012-12-01T21:30:16.477 に答える
0

これを行う1つの方法は、Pythonセットを使用することです。

#Get the set of conversation ids for each participant
    p1_conv_set = set(Converstation.objects.filter(participants = p1).values_list('id', flat=True))
    p2_conv_set = set(Converstation.objects.filter(participants = p2).values_list('id', flat=True))
    .
    .
    pn_conv_set = set(Converstation.objects.filter(participants = pN).values_list('id', flat=True))
    #Find the common ids for all participants
    all_participants_intersection = p1_conv_set & p2_conv_set & ....pN_conv_set
    #Get all the conversation for all the calculated ids
    Conversation.objects.filter(id__in = all_participants_intersection)
于 2012-12-01T23:32:30.247 に答える