2

I have a simple chat application with a GraphQL API written in Django with Graphene plugin. And an Angular UI with Apollo as the GraphQL client. I have a chat model that is like chat rooms and a chatMessage model that is more of the individual message that is tied to the chat model via a foreignKey field, so that every chat message is tied to some chat item.

The following is the model specification in Django:-

class Chat(models.Model):
    name = models.CharField(max_length=100, blank=True, null=True)

    admins = models.ManyToManyField(User, related_name="adminInChats", through="ChatAdmin", through_fields=(
        'chat', 'admin'), blank=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 ChatAdmin(models.Model):
    chat = models.ForeignKey(Chat, on_delete=models.CASCADE)
    admin = models.ForeignKey(User, on_delete=models.CASCADE)

    def __str__(self):
        return self.chat


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


class ChatMessage(models.Model):
    chat = models.ForeignKey(Chat, on_delete=models.PROTECT)
    message = models.CharField(max_length=1000)
    author = models.ForeignKey(
        User, related_name="chatAuthor", on_delete=models.DO_NOTHING)
    seenBy = models.ForeignKey(
        User, related_name="chatSeenBy", on_delete=models.PROTECT, blank=True, null=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    def __str__(self):
        return self.chat

And I'm using GraphQL to fetch an individual chat item. The following is the backend code for it:-

class Query(ObjectType):

    chat = graphene.Field(ChatType, id=graphene.ID())

    @login_required
    def resolve_chat(root, info, id, **kwargs):
        chat_instance = Chat.objects.get(pk=id, active=True)
        if chat_instance is not None:
            return chat_instance
        else:
            return None

and I call it with this using my Apollo Client on Angular:-

  GET_CHAT: gql`
    query chat($id: ID!) {
      chat(id: $id) {
        id
        name
        admins {
          id
          firstName
          lastName
        }
        members {
          id
          firstName
          lastName
        }
        chatmessageSet {
          message
          author {
            id
            firstName
            avatar
          }
          createdAt
          seenBy {
            firstName
          }
        }
        createdAt
      }
    }
  `,

So when I make this query from the client, I want it to send just the first 30 messages in that chatmessageSet. Right now it sends me everything and that's not good for the traffic. I want to paginate the messages basically.

I know how to do everything else for the pagination, but I am not familiar enough with backend coding in Django to know how to specify the resolve_chat method so that it sends me only the first 30 chat messages belonging to that chat, sorted by descending id, whenever it is requested.

How do I write the resolve_chat method?

Ragav Y
  • 1,662
  • 1
  • 18
  • 32

1 Answers1

1

This is a good candidate for using relay. First, you need to define a ChatMessageType if you don't already and set its interface to relay.Node:

class ChatMessageType(DjangoObjectType):
    class Meta:
        model = ChatMessage
        fields = ("message", "author", "seenBy")
        interfaces = (graphene.relay.Node,)

Then on your ChatType, define a DjangoFilterConnectionField like so:

class ChatType(DjangoObjectType):
    ...
    chat_messages = DjangoFilterConnectionField("ChatMessageType")

You can then query it like this to limit the result

chat(id: $id) {
  ...
  chatMessages(first: 30) {
    message,
    author,
    seenBy
  }
  ...
}
Jerven Clark
  • 1,191
  • 2
  • 13
  • 26