Django rest framework – tworzenie użytkowników

Na wstępie tworzę nową aplikację o nazwie users tzn.

python manage.py startapp users

W pliku models.py tworzę niestandardowego użytkownika, który dziedziczy po klasie AbstractUser. Dodaję pole wyboru role, dzięki czemu użytkownik będzie należał albo do zleceniodawców, albo do zleceniobiorców (client lub contractor).

from django.contrib.auth.models import AbstractUser
from django.db import models


class ContractUser(AbstractUser):
    class RoleChoices(models.TextChoices):
        CLIENT = "client"
        CONTRACTOR = "contractor"

    role = models.CharField(
        max_length=10,
        choices=RoleChoices.choices, default=RoleChoices.CLIENT
    )

    def __str__(self):
        return self.username

Nowy model user należy zarejestrować w pliku settings.py projektu, tzn.

AUTH_USER_MODEL = "users.ContractUser"

W aplikacji users tworzę plik serializers.py zawierający serializer nowego modelu użytkownika tzn.

from django.contrib.auth.hashers import make_password
from rest_framework import serializers
from .models import ContractUser


class ContractUserSerializer(serializers.ModelSerializer):
    password = serializers.CharField(
        min_length=8,
        write_only=True,
        style={"input_type": "password"}
    )

    class Meta:
        model = ContractUser
        fields = [
             "id",
             "username",
             "password",
             "email",
             "role"
        ]

    def create(self, validated_data):
        validated_data["password"] = make_password(validated_data["password"])
        return super().create(validated_data)

Serializer zawiera pole tekstowe umożliwiające wprowadzenie pola tekstowego dla hasła. Pole to zawiera parametr write_only ustawione na wartość True, aby możliwy był tylko zapis, a nie odczyt tego pola. Pole fields klasy wewnętrznej Meta zawiera listę wszystkich dostępnych pól do serializacji. Metoda create() tworzy hasło na podstawie wprowadzonych przez użytkownika danych przy użyciu funkcji make_password().

W pliku urls.py aplikacji users definiuję punkt dostępowy tzn.

from rest_framework.routers import DefaultRouter
from .views import ContractUserCreateRetrieveViewSet

router = DefaultRouter()

router.register("", ContractUserCreateRetrieveViewSet, basename="user")

urlpatterns = router.urls

Punkt dostępowy dla aplikacji users dołączam do głównego pliku urls.py projektu:

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path("admin/", admin.site.urls),
    path("api/user/", include("users.urls")),
]

Punkt dostępowy /api/user/ będzie umożliwiał tworzenie użytkownika i podgląd danych dla danego użytkownika. W tym celu w pliku views.py tworzę klasę ContractUserCreateRetrieveViewSet(). Aby ograniczyć liczbę dostępnych metod nie korzystam z klasy ModelViewSet, ale dziedziczę po klasie GenericViewSet oraz odpowiednich klasach Mixin.

from django.shortcuts import get_object_or_404
from rest_framework import viewsets, mixins
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework import status
from .models import ContractUser
from .serializers import ContractUserSerializer

class ContractUserCreateRetrieveViewSet(
    mixins.CreateModelMixin,
    mixins.RetrieveModelMixin,
    viewsets.GenericViewSet,
):
    serializer_class = ContractUserSerializer
    queryset = ContractUser.objects.all()

    def retrieve(self, request, pk):
        permission_classes = [IsAuthenticated]
        queryset = ContractUser.objects.filter(id=request.user.id)
        user = get_object_or_404(queryset, pk=pk)
        serializer = ContractUserSerializer(user)
        return Response(serializer.data)

    def create(self, request):
        serializer = ContractUserSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        else:
            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

Aby nowo utworzony użytkownik miał status nieaktywny skorzystałem z sygnału pre_save. W tym celu utworzyłem nowy plik signals.py w aplikacji users tzn.

from django.db.models.signals import pre_save
from .models import ContractUser
from django.dispatch import receiver

@receiver(pre_save, sender=ContractUser)
def create_inactive_user(sender, instance, **kwargs):
    instance.is_active = False

Sygnał należy zaimportować w funkcji ready() klasy UsersConfig() z pliku apps.py

from django.apps import AppConfig


class UsersConfig(AppConfig):
    default_auto_field = "django.db.models.BigAutoField"
    name = "users"

    def ready(self):
        import users.signals

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *

50 ÷ 5 =