DEV Community

Cover image for Django and React Chat App: part-2
Mousa Aboubaker
Mousa Aboubaker

Posted on

Django and React Chat App: part-2

Welcome to the second part
in the previous part, we finished our models
in this part we are going to set our views.py and urls.py files

first, let's install the required libraries and frameworks

pip install djangorestframework django-filter djangorestframework-simplejwt django-cors-headers
Enter fullscreen mode Exit fullscreen mode

let's add some changes to our settings.py file
add these to INSTALLED_APPS

INSTALLED_APPS = [
    ...,
    'django.contrib.staticfiles',
    'django_resized',
    'rest_framework',
    'chat',
    'rest_framework_simplejwt.token_blacklist',
    'corsheaders',
]
Enter fullscreen mode Exit fullscreen mode

now we are going to create REST_FRAMEWORK dictionary

REST_FRAMEWORK = {
    'DEFAULT_FILTER_BACKENDS': [
        'django_filters.rest_framework.DjangoFilterBackend'
    ],
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework_simplejwt.authentication.JWTAuthentication',
    ],
    'DEFAULT_RENDERER_CLASSES': (
        'rest_framework.renderers.JSONRenderer',
    )
}
Enter fullscreen mode Exit fullscreen mode

now we'll add SIMPLE_JWT dictionary under the previous one

SIMPLE_JWT = {
    'ACCESS_TOKEN_LIFETIME': timedelta(minutes=90),
    'REFRESH_TOKEN_LIFETIME': timedelta(days=90),
    'ROTATE_REFRESH_TOKENS': True,
    'BLACKLIST_AFTER_ROTATION': True,
    'UPDATE_LAST_LOGIN': False,

    'ALGORITHM': 'HS256',
    'SIGNING_KEY': SECRET_KEY,
    'VERIFYING_KEY': None,
    'AUDIENCE': None,
    'ISSUER': None,
    'JWK_URL': None,
    'LEEWAY': 0,

    'AUTH_HEADER_TYPES': ('Bearer',),
    'AUTH_HEADER_NAME': 'HTTP_AUTHORIZATION',
    'USER_ID_FIELD': 'id',
    'USER_ID_CLAIM': 'user_id',
    'USER_AUTHENTICATION_RULE': 'rest_framework_simplejwt.authentication.default_user_authentication_rule',

    'AUTH_TOKEN_CLASSES': ('rest_framework_simplejwt.tokens.AccessToken',),
    'TOKEN_TYPE_CLAIM': 'token_type',
    'TOKEN_USER_CLASS': 'rest_framework_simplejwt.models.TokenUser',

    'JTI_CLAIM': 'jti',

    'SLIDING_TOKEN_REFRESH_EXP_CLAIM': 'refresh_exp',
    'SLIDING_TOKEN_LIFETIME': timedelta(minutes=5),
    'SLIDING_TOKEN_REFRESH_LIFETIME': timedelta(days=1),
}
Enter fullscreen mode Exit fullscreen mode

here
ACCESS_TOKEN_LIFETIME is the lifetime for the access token that will be used in JWT authorization, I set it to 90 minutes
REFRESH_TOKEN_LIFETIME is the lifetime for the refresh token that will be used to refresh the access token, I set it to 90 days (you can change as you want)
ROTATE_REFRESH_TOKENS it lets me to change the refresh token when I want and get new one
BLACKLIST_AFTER_ROTATION when the token will be rotated in the previous key, it will gives me a new token, but without blacklist I will be able to use the old token, but when I set this key to True it will takes the old token to a blacklist and you can't use it anymore

those are the most important keys I mentioned, to see the full keys and their uses, visit this link:

now let's add some CORS (Cross-Origin Resource Sharing) configuration
add this in MIDDLEWARE list

MIDDLEWARE = [
    ...,
    "corsheaders.middleware.CorsMiddleware",
    "django.middleware.common.CommonMiddleware",
    ...,
]
Enter fullscreen mode Exit fullscreen mode

then add these under MIDDLEWARE list

CORS_ALLOW_CREDENTIALS = True
CORS_ALLOWED_ORIGINS = [
    'http://localhost:5173',
    'http://localhost:5174',
    'http://127.0.0.1:5173',
    'http://127.0.0.1:5174'
]
Enter fullscreen mode Exit fullscreen mode

the CORS_ALLOWED_ORIGINS list includes the websites that can use our api, I set it to my localhost websites, when you are going to deploy your app, you must change it or add to them your website link

now we configured our settings.py file, let's run these commands to make new models (came already with blacklist, so, we need to run these commands to make sure our app will run correctly)

python manage.py makemigrations
python manage.py migrate
Enter fullscreen mode Exit fullscreen mode

now, we are going to make new file inside chat folder and name it serializers.py and call our Chat model and drf inside it

from rest_framework.serializers import ModelSerializer, SerializerMethodField
from .models import Chat
Enter fullscreen mode Exit fullscreen mode

now let's write our serializer
first, we'll make ModelSerializer with our model Chat in serializer class ChatSerializer

class ChatSerializer(ModelSerializer):
    class Meta:
        model = Chat
        fields = '__all__'
Enter fullscreen mode Exit fullscreen mode

now, our chat serializer works with our chat model and choose the whole fields in our chat model
later in the views and when we'll connect with frontend, we'll face a problem with user field because it'll return the id of the user not the name of it, so we need to change our serializer like this

class ChatSerializer(ModelSerializer):
    user = SerializerMethodField("get_name")
    class Meta:
        model = Chat
        fields = '__all__'
    def get_name(self, obj):
        return obj.user.username
Enter fullscreen mode Exit fullscreen mode

now we changed user field as depicted above, we called SerializerMethodField function and insert another function inside it, this function we'll return the user's name instead of the user id
now our simple serializer is ready

now, let's start with our views.py file
let's write these lines of code, I copied them from drf website and pasted them in our file

from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
from rest_framework_simplejwt.views import TokenObtainPairView

class MyTokenObtainPairSerializer(TokenObtainPairSerializer):
    @classmethod
    def get_token(cls, user):
        token = super().get_token(user)

        token['username'] = user.username

        return token

class MyTokenObtainPairView(TokenObtainPairView):
    serializer_class = MyTokenObtainPairSerializer
Enter fullscreen mode Exit fullscreen mode

I got these classes from djangorestframework-simplejwt docs, you can find them here:



we'll use these classes later in our urls.py file, now let's continue with our views.py

now we are going to create a function to create users

firstly, import these in the top of the file

import json
from django.http import JsonResponse
from django.contrib.auth.models import User
from rest_framework.decorators import api_view
Enter fullscreen mode Exit fullscreen mode

we need to import json to loads our body from the frontend
JsonResponse is to give json response to our frontend
User model has the whole users inside it and we need it to create users
api_view is a decorator from drf decorators, and it used with fbv (Function Based Views) to make sure that it'll get post request only

now let's create our first views function, to make new users

@api_view(['POST'])
def createUser(request):
    if request.method == "POST":
        data = json.loads(request.body)
        username = data['username']
        password = data['password']
        try:
            User.objects.get(username=username)
            return JsonResponse({"status": "405", "ok": False})
        except:
            User.objects.create_user(username=username, password=password).save()
            return JsonResponse({"status": "200", "ok": True})
Enter fullscreen mode Exit fullscreen mode

we create a function and give it a decorator to get only post request with our api
inside the function, I make a condition to make sure that the request is post and do the rest of the work
inside the condition, we'll load our json body (request from frontend) to data variable
make two variables username and password and give the json body values to them
then, we'll make try and except to make sure that the user isn't repeated (it must be unique), if the user name is already exists , it'll return json response, with status 405 and false ok response
otherwise, the user will be created and return 200 ok response
Note: use create_user instead of the known one create, because create_user make users with hashed passwords
our first function is completed, let's start with the next
now, we'll import these

from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import IsAuthenticated
from .models import Room
Enter fullscreen mode Exit fullscreen mode

we imported another decorator and a permission to make sure the user that make request is authenticated and import our Room model
now let's create a new function to create rooms

@api_view(['POST'])
@permission_classes([IsAuthenticated])
def createRoom(request):
    if request.method == "POST":
        data = json.loads(request.body)
        try:
            Room.objects.get(name = data['name'], password = data['password'])
            return JsonResponse({"status": 404})
        except:
            Room.objects.create(name = data['name'], password = data['password'])
            return JsonResponse({"status": 200})
Enter fullscreen mode Exit fullscreen mode

it is similar to CreateUser function, except that we give it another decorator, permission_classes and give it IsAuthenticated permission to make sure that the user who try to create new room is already authenticated, and the rest of the function is similar to the previous one
that's all to this article, in the next one I'll show you how to create a new function to show and create chat messages and to delete room (if you want)
See you in the next part
this is the Github repository for this chat project, don't forget to give it a star

# django-react-chat-app
this is a simple chat app built with django and react

# how to run this project
make a virtual environment and install the repository inside it

activate you virtual environment
```bash
venv/Scripts/activate # for linux: source venv/bin/activate
```

then take a dive inside backend folder and download the used packages
```bash
pip install -r requirements.txt
```

then run the server

```bash
python manage.py runserver
```
**Note: make sure that the virtual environment is activated**

Now get inside the frontend folder and run
```bash
npm i # or npm install
```
and then run the website
```bash
npm run dev
```

Happy Coding ^_^



Happy Coding ^_^

Top comments (0)