Reputation: 18735
I'm trying to create a Model
which represents a conversation between two users (only two).
Can't figure out how to create two fields because users are equivalent.
class Conversation(models.Model):
user_one = ForeignKey('auth.User')
user_two = ForeignKey('auth.User')
class Meta:
unique_together = ('user_one','user_two')
Is this the best way I can design a model?
And then manager method:
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
Or is there a more comfortable way to handle such model? For example using ManyToManyField
and check if there are two and only two users?:
users = ManyToManyField('auth.User')
Upvotes: 1
Views: 580
Reputation: 2475
Use the related_name
field when you have more than 1 foreign key to the same model. Because you often don't care who specifically is user_one and user_two, you can simply make sure that user_one and user_two are consistent. In this case, I'm using the user's id field to say which user will be user_one and which will be user_two. This makes querying simpler because you don't need to do a query for the two pairs (A, B) and (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)
Upvotes: 2
Reputation: 996
If you are using postgres you could use an ArrayField:
class Conversation(models.Model):
users = ArrayField(
ForeignKey('auth.User'),
size=2,
)
That would help with lookups. However note what the documentation currently says about the size
parameter:
This is an optional argument. If passed, the array will have a maximum size as specified. This will be passed to the database, although PostgreSQL at present does not enforce the restriction.
Upvotes: 0