【发布时间】:2021-09-11 11:13:05
【问题描述】:
我正在构建一个用于聊天应用程序的 Django GraphQL API。我有以下 2 种模型,一种用于聊天,一种用于聊天成员,它们作为外键绑定:-
class Chat(models.Model):
name = models.CharField(max_length=100, blank=True, null=True)
members = models.ManyToManyField(User, related_name="privateChats",
through="ChatMember", through_fields=('chat', 'member'), blank=True)
active = models.BooleanField(default=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
return self.name
class ChatMember(models.Model):
chat = models.ForeignKey(Chat, on_delete=models.CASCADE)
member = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return self.chat
我有一种方法应该接受 2 个用户 ID,首先它会检查这 2 个成员之间是否存在现有聊天。如果存在,则返回该聊天。如果不是,那么它会为这 2 个成员创建一个新聊天并返回新创建的聊天。
棘手的部分是它尝试搜索是否存在现有聊天。因为我在群聊中使用了相同的聊天模型,所以它可能会返回一个也有这 2 个成员的群组。因此,检查这 2 个成员之间是否存在一对一聊天的条件是,首先检查聊天中是否只有 2 个成员,并且这 2 个成员具有我作为该方法的输入获得的 id。
我对 Django 和 Python 非常陌生,所以我不知道要编写查询来查找是否存在这样的聊天。到目前为止,这就是我为此所做的:-
class ChatWithMember(graphene.Mutation):
class Meta:
description = "Mutation to get into a Chat"
class Arguments:
# ***This is the first user's Id.***
id = graphene.ID(required=True)
ok = graphene.Boolean()
chat = graphene.Field(ChatType)
@staticmethod
@login_required
def mutate(root, info, id):
ok = True
# ***Second user's id is taken from the request***
current_user = info.context.user
member = User.objects.get(pk=id)
if member is None:
return ChatWithMember(ok=False, chat=None)
# ***First I annotate the number of members in 'individual_chats'***
individual_chats = Chat.objects.annotate(member_count=Count('members'))
# ***Then I filter those chats that have only 2 members***
individual_chats = individual_chats.filter(member_count=2)
# ***Then I loop through those to check if there's one that has the two members in that chat and if it exists, I return it.***
for chat in individual_chats.all():
if current_user.id in chat.members and member.id in chat.members:
return ChatWithMember(ok=ok, chat=chat)
chat_instance = Chat()
chat_instance.save()
# Adding the creator of the chat and the member
chat_instance.members.set([current_user.id, id])
return ChatWithMember(ok=ok, chat=chat_instance)
目前我收到错误__str__ returned non-string (type NoneType),之前我收到了TypeError: ManyRelatedManager object is not iterable。我在这方面花了很多时间,显然我需要一些帮助。
我根据自己对如何完成它的理解编写了这个方法,但我不确定是否存在更简单的方法。请告诉我该怎么做。
更新:-
我根据@Henri 的建议修改了方法:-
def mutate(root, info, id):
ok = True
current_user = info.context.user
member = User.objects.get(pk=id)
if member is None:
return ChatWithMember(ok=False, chat=None)
individual_chats = Chat.objects.annotate(member_count=Count('members'))
individual_chats = individual_chats.filter(member_count=2)
print('Individual chats before try => ',
individual_chats.values_list('name', 'members__id'))
try:
chats_with_these_2_members = individual_chats.get(
members__in=[member, current_user])
return ChatWithMember(ok=ok, chat=chats_with_these_2_members)
except MultipleObjectsReturned:
print('multiple chats found!')
return ChatWithMember(ok=False, chat=None)
# Error because multiple chats found with these 2 members (and only them)
except Chat.DoesNotExist:
print('Creating new chat')
chat_instance = Chat()
chat_instance.save()
# Adding the creator of the chat and the member
chat_instance.members.set([current_user.id, id])
return ChatWithMember(ok=ok, chat=chat_instance)
有了这个,当我尝试使用已经与他们聊天的两个用户作为仅有的 2 个成员触发此方法时,我在控制台中得到以下输出:-
Individual chats before try => <QuerySet []> Creating new chat
所以基本上它无法识别符合条件的聊天的存在并继续并创建一个新的聊天。
更糟糕的是,如果我在创建第一个聊天后尝试与不同的成员组合发起聊天,我会得到:-
Individual chats before try => <QuerySet []> multiple chats found!
这意味着它不再为不同的成员组合创建新的聊天。
这部分有很大的问题:-
try:
chats_with_these_2_members = individual_chats.get(
members__in=[member, current_user])
return ChatWithMember(ok=ok, chat=chats_with_these_2_members)
except MultipleObjectsReturned:
print('multiple chats found!')
return ChatWithMember(ok=False, chat=None)
# Error because multiple chats found with these 2 members (and only them)
except Chat.DoesNotExist:
但我不知道如何解决它,因为我对 Python 太陌生了。
【问题讨论】: