Django and React Chat App: part-2
Tags: django, react, javascript, webdev
Published: 2022-12-02 16:13:11

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
```bash
pip install djangorestframework django-filter djangorestframework-simplejwt django-cors-headers
```

let's add some changes to our settings.py file
add these to __INSTALLED_APPS__
```python
INSTALLED_APPS = [
    ...,
    'django.contrib.staticfiles',
    'django_resized',
    'rest_framework',
    'chat',
    'rest_framework_simplejwt.token_blacklist',
    'corsheaders',
]
```

now we are going to create **REST_FRAMEWORK** dictionary
```python
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',
    )
}
```
now we'll add **SIMPLE_JWT** dictionary under the previous one
```python
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),
}
```
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:
{% embed https://django-rest-framework-simplejwt.readthedocs.io/en/latest/settings.html %}

now let's add some CORS (Cross-Origin Resource Sharing) configuration
add this in **MIDDLEWARE** list
```python
MIDDLEWARE = [
    ...,
    "corsheaders.middleware.CorsMiddleware",
    "django.middleware.common.CommonMiddleware",
    ...,
]
```
then add these under **MIDDLEWARE** list
```python
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'
]
```
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)
```bash
python manage.py makemigrations
python manage.py migrate
```

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
```python
from rest_framework.serializers import ModelSerializer, SerializerMethodField
from .models import Chat
```
now let's write our serializer
first, we'll make ModelSerializer with our model **Chat** in serializer class **ChatSerializer**
```python
class ChatSerializer(ModelSerializer):
    class Meta:
        model = Chat
        fields = '__all__'
```
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
```python
class ChatSerializer(ModelSerializer):
    user = SerializerMethodField("get_name")
    class Meta:
        model = Chat
        fields = '__all__'
    def get_name(self, obj):
        return obj.user.username
```
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
```python
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
```
I got these classes from djangorestframework-simplejwt docs, you can find them here: {% embed https://django-rest-framework-simplejwt.readthedocs.io/en/latest/customizing_token_claims.html %}
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
```python
import json
from django.http import JsonResponse
from django.contrib.auth.models import User
from rest_framework.decorators import api_view
```
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
```python
@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})
```
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
```python
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import IsAuthenticated
from .models import Room
```
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
```python
@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})
```
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
{% embed https://github.com/MasterMousa/django-react-chat-app %}
Happy Coding ^_^