【问题标题】:Django model: Conversation between two usersDjango 模型:两个用户之间的对话
【发布时间】:2018-05-03 23:21:45
【问题描述】:

我正在尝试创建一个Model,它代表两个用户(只有两个)之间的对话。

不知道如何创建两个字段,因为用户是等价的。

class Conversation(models.Model):
    user_one = ForeignKey('auth.User')
    user_two = ForeignKey('auth.User')

    class Meta:
         unique_together = ('user_one','user_two')

这是我设计模型的最佳方式吗?

然后是管理器方法:

def get_conversation(user_one,user_two):
    c = Conversation.objects.filter(Q(user_one=user_one,user_two=user_two)|Q(user_one=user_one,user_two=user_two))
    return c

或者有没有更舒适的方法来处理这种模型?例如使用ManyToManyField 并检查是否有两个且只有两个用户?:

users = ManyToManyField('auth.User') 

【问题讨论】:

    标签: python django database postgresql django-models


    【解决方案1】:

    当您对同一模型有多个外键时,请使用 related_name 字段。因为您通常不关心 user_one 和 user_two 具体是谁,所以您可以简单地确保 user_one 和 user_two 是一致的。在这种情况下,我使用用户的 id 字段来说明哪个用户是 user_one,哪个是 user_two。这使得查询更简单,因为您不需要对 (A, B) 和 (B, A) 两对进行查询

    class Conversation(models.Model):
        user_one = ForeignKey('auth.User', related_name="user_one")
        user_two = ForeignKey('auth.User', related_name="user_two")
    
        class Meta:
            unique_together = ('user_one','user_two')
    
        def clean(self):
            # Ensure that user_one's id is always less than user_two's
            if self.user_one and self.user_two and self.user_one.id > self.user_two.id:
                (self.user_one, self.user_two) = (self.user_two, self.user_one)
    
        @classmethod
        def get(cls, userA, userB):
            """ Gets all conversations between userA and userB
            """
    
            if userA.id > userB.id:
                (userA, userB) = (userB, userA)
    
            return cls.objects.filter(user_one=userA, user_two=userB)
    

    【讨论】:

    • 我不是在询问相关名称。我只是不认为这是最好的方法,因为用户是完全等价的。对于两个不同的用户,查找可能会有点混乱。
    • @MilanoSlesarik Gotcha,所以如果您认识 2 个用户并想查询他们一起进行了哪些对话,您必须执行 user_one=A, user_two=B,反之亦然。可能有一种我不知道的好方法,但是如果您将哪个用户归一化怎么办?例如,user_one 始终是 id 最小的用户。您可以编写一个简单的助手来检索给定 2 个用户的对话,并将一些逻辑放入 clean 方法中,如果用户的 ID 顺序不正确,则该方法将交换用户
    • 编辑答案以包含示例
    【解决方案2】:

    如果您使用的是 postgres,您可以使用 ArrayField:

    class Conversation(models.Model):
        users = ArrayField(
            ForeignKey('auth.User'),
            size=2,
        )
    

    这将有助于查找。但是请注意文档当前对size 参数的说明:

    这是一个可选参数。如果通过,数组将具有指定的最大大小。这将被传递给数据库,尽管 PostgreSQL 目前不强制执行限制。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-08-04
      • 2016-06-15
      • 2019-02-13
      • 2010-10-22
      • 1970-01-01
      相关资源
      最近更新 更多