Getting Started

Quickstart Guide

We are going to create a simple blog application with a gRPC service. The blog application will have the following models: User and Post.

Prerequisites

You will need to install the following packages:

  • Python (>= 3.8)

Installation

Install the package via pip:

pip install django-socio-grpc

Creating a New Project

Now you can create the project by running the following command :

django-admin startproject tutorial

Add now the following lines to the INSTALLED_APPS section of your tutorial/settings.py file:

INSTALLED_APPS = [
  ...
  'django_socio_grpc',
]

Adding a New App

Then create a new app. First, cd into the project directory:

cd tutorial

Create the new app:

python manage.py startapp quickstart

This will create a new directory called quickstart inside your project directory including python files.

Add the new app to the INSTALLED_APPS section of your tutorial/settings.py file:

INSTALLED_APPS = [
  ...
  'quickstart',
]

Finally migrate the database:

python manage.py migrate

Defining models

Models are created in the same way as in Django (Django documentation) . Each model is assigned to a table in the database. It inherits from a Python class django.db.models.Model. Each attribute represents a field in the table. The API for accessing the database is the same as Django’s (Query creation).

#quickstart/models.py
from django.db import models
class User(models.Model):
full_name = models.CharField(max_length=70)

class Post(models.Model):
    pub_date = models.DateField()
    headline = models.CharField(max_length=200)
    content = models.TextField()
    user = models.ForeignKey(User, on_delete=models.CASCADE)

Defining serializers

In this example, our serializers inherit from ModelProtoSerializer, which is simply an inheritance of DRF’s ModelSerializer. For more extensive use, you can use all the DRF serializer methods: Django REST framework serializers.

#quickstart/serializers.py
from django_socio_grpc import proto_serializers
from rest_framework import serializers
from quickstart.models import User, Post

class UserProtoSerializer(proto_serializers.ModelProtoSerializer):
    # This line is written here as an example,
    # but can be removed as the serializer integrates all the fields in the model
    full_name = serializers.CharField(allow_blank=True)
    class Meta:
        model = User
        fields = "__all__"

class PostProtoSerializer(proto_serializers.ModelProtoSerializer):
    pub_date = serializers.DateTimeField(read_only=True)
    user = serializers.PrimaryKeyRelatedField(
        queryset=User.objects.all(),
        pk_field=serializers.UUIDField(format="hex_verbose"),
    )

    class Meta:
        model = Post
        fields = "__all__"

Defining gRPC services

Whereas DRF uses APIView, Django Socio gRPC uses Service. With the exception of the gRPC internal layer, a Service is made to work in the same way as a generic DRF APIView.

Django Socio gRPC Framework also supports both sync and async. In this quickstart, we will make an asynchronous service.

Following the same logic as DRF, Django Socio gRPC uses class-based services.

DSG mixins make it easy to declare one or several of the CRUD actions. Please refer to the Mixin section for more information.

In the the following example we will create 2 services.

  • UserService, will be a read-only service (AsyncReadOnlyModelService), meaning that it will have 2 gRPC actions: List and Retrieve.

  • PostService, will be a read-write service (AsyncModelService), meaning that it will have 6: List, Retrieve, Create, Update, PartialUpdate, Destroy.

    #quickstart/services.py
    from django_filters.rest_framework import DjangoFilterBackend
    from rest_framework.pagination import PageNumberPagination
    from django_socio_grpc import generics
    
    from quickstart.models import User, Post
    from quickstart.serializer import UserProtoSerializer, PostProtoSerializer
    
    class UserService(generics.AsyncReadOnlyModelService):
        queryset = User.objects.all()
        serializer_class = UserProtoSerializer
    
    class PostService(generics.AsyncModelService):
        queryset = Post.objects.all()
        serializer_class = PostProtoSerializer
    

Note:

DSG Generic services and mixins are based on DRF Generic views and mixins.

In DSG :

from django.contrib.auth.models import User
from quickstart.serializers import UserProtoSerializer
from django_socio_grpc import generics

class MyListService(generics.ListCreateService):
        queryset = User.objects.all()
        serializer_class = UserProtoSerializer

In DRF :

from django.contrib.auth.models import User
from quickstart.serializers import UserProtoSerializer
from rest_framework import generics

class MyListService(generics.ListCreateAPIView):
        queryset = User.objects.all()
        serializer_class = UserProtoSerializer

Register services

You need to register your services in a handler function. This handler will be the entrypoint for your whole app. In this quickstart, we will register our services in the quickstart/handlers.py file.

# quickstart/handlers.py
from django_socio_grpc.services.app_handler_registry import AppHandlerRegistry
from quickstart.services import UserService, PostService


def grpc_handlers(server):
    app_registry = AppHandlerRegistry("quickstart", server)
    app_registry.register(UserService)
    app_registry.register(PostService)

Set its path as the ROOT_HANDLERS_HOOK of the GRPC_FRAMEWORK settings:

# quickstart/settings.py
...
GRPC_FRAMEWORK = {
    "ROOT_HANDLERS_HOOK" : 'quickstart.handlers.grpc_handlers',
    ...
}

Generate the app’s Protobuf files and gRPC stubs

Run this command :

python manage.py generateproto

This will generate a folder called grpc at the root of your Django app. It contains the three files describing your new gRPC service:

  • quickstart_pb2_grpc.py

  • quickstart_pb2.py

  • quickstart.proto

DSG generate all the file needed by gRPC. Meaning that you don’t need to deal with protofile manually.

Assign newly generated classes

In the quickstart/grpc/quickstart.proto file, you can find the generation of the structure of responses and requests. For each serializer, you will find the basic Response message name and the ListResponse message name. Serializers need to be assigned to these gRPC messages, which are defined in the pb2 file. You need to import the messages in the serializers.py file and assign them to the serializers.

#quickstart/serializers.py
...
from quickstart.grpc.quickstart_pb2 import (
    UserResponse,
    UserListResponse,
    PostResponse,
    PostListResponse,
)

class UserProtoSerializer(proto_serializers.ModelProtoSerializer):
    ...
    class Meta:
        ...
        proto_class = UserResponse
        proto_class_list = UserListResponse

class PostProtoSerializer(proto_serializers.ModelProtoSerializer):
    ...
    class Meta:
        ...
        proto_class = PostResponse
        proto_class_list = PostListResponse

Running the Server

You can now run the server with the following command:

python manage.py grpcrunaioserver --dev

The server is now running on port 50051 by default. See How To to see how to call this server with python or web client.