Как обновить профиль пользователя в Django с помощью Django REST API Framework?

Обзор системы

В моей системе есть 5 различных типов пользователей (администраторы, сотрудники, клиенты, студенты и преподаватели). Клиент, владеющий собственным профилем, может обновлять информацию своего профиля. Он/она не имеет права обновлять информацию профиля других клиентов.

Я не получаю ожидаемый результат, как сказано выше.

models.py

Этот файл включает 2 модели (UserAccount и ClientProfile)

class UserAccount(AbstractBaseUser, PermissionsMixin):

    email = models.EmailField(verbose_name="Email Address", max_length=255, unique=True)
    full_name = models.CharField(verbose_name="Full Name", max_length=255)
    date_joined = models.DateTimeField(verbose_name="Member Since", auto_now_add=True)
    last_login = models.DateTimeField(verbose_name="Last Logged In", auto_now=True)
    is_verified = models.BooleanField(default=False)

    is_admin = models.BooleanField(default=False)
    is_staff = models.BooleanField(default=False)
    is_superuser = models.BooleanField(default=False)

    is_client = models.BooleanField(default=False)
    is_student = models.BooleanField(default=False)
    is_teacher = models.BooleanField(default=False)

    is_active = models.BooleanField(default=True)

    USERNAME_FIELD = "email"
    REQUIRED_FIELDS = ["full_name", ]

    objects = UserAccountManager()

    class Meta:
        db_table = 'USERS_INFORMATION'
        verbose_name = "Users Account"
        verbose_name_plural = "Users Accounts"

    def __str__(self):
        return self.full_name

    def get_name(self):
        return self.full_name

    def get_email(self):
        return self.email

class ClientProfile(models.Model):

    class Meta:
        db_table = 'CLIENTS_PROFILE_INFORMATION'
        verbose_name = "Clients Profile Account"
        verbose_name_plural = "Clients Profile Accounts"

    client = models.OneToOneField(UserAccount, on_delete=models.CASCADE, related_name="client")
    country = models.CharField(verbose_name="Country", max_length=100, blank=True, null=True)
    is_client = models.BooleanField(default=True)

    def __str__(self):
        return self.client.full_name

    def get_email(self):
        return self.client.email

    def get_dateJoined(self):
        return self.client.date_joined

    def get_lastLoggedIn(self):
        return self.client.last_login

    def get_isVerified(self):
        return bool(self.client.is_verified)

    get_isVerified.boolean = True

    def get_country(self):
        return self.country

    get_email.short_description = "Email Address"
    get_dateJoined.short_description = "Member Since"
    get_lastLoggedIn.short_description = "Last Logged In"
    get_isVerified.short_description = "Is Email Address Verified"

Я использую пользовательское разрешение, чтобы позволить владельцам клиентов получить доступ к их собственному профилю.

permissions.py

class ClientProfileUpdateViewPermission(BasePermission):
    message = "Only Client who is the Owner of their profile can View / Edit their own Profile Information"
        
    def has_object_permission(self, request, view, object):
        if request.method in SAFE_METHODS:
            return True
        return object.id == request.user.id

Я использую RetrieveUpdateAPIView Generic Class Based View

class ClientProfileUpdateAPIView(RetrieveUpdateAPIView):
    authentication_classes = (JWTAuthentication, )
    permission_classes = (ClientProfileUpdateViewPermission, )
    
    def get(self, request, client_id, format=None):
        client_profile = ClientProfile.objects.get(client_id=client_id)

        if client_profile.country == None:
            client_profile.country = "-"

        if client_profile.get_isVerified():
            account_status = "Verified"
        else:
            account_status = "Not Verified"

        client_profile_information = {
            "Client Full Name" : client_profile.__str__(),
            "Client Email Address" : client_profile.get_email(),
            "Client Since" : client_profile.get_dateJoined(),
            "Last Logged In" : client_profile.get_lastLoggedIn(),
            "Country" : client_profile.get_country(),
            "Account Status" : account_status,
        }

        return Response(client_profile_information, status=HTTP_200_OK)

urls.py

path("clients/<int:client_id>/update", ClientProfileUpdateAPIView.as_view(), name="client-profile-update"),

Я использую Postman Agent для тестирования API. Я также использую простую аутентификацию и авторизацию пользователей JWT, поэтому передаю Authorization Bearer <token> также в Postman Agent.

Для клиента ID: 26 я получаю токен и передаю его в секции Header как Authorization Bearer, и когда я отправляю запрос для всех различных 3 клиентов (ID: 3, 6, 26), я получаю всю информацию о других клиентах. Но я хочу обновить только ID клиента 26. Для клиентов ID: 3 и 6, будет получен ответ Forbidden Response.

Client ID: 3

Client ID: 6

Client ID: 26

Я знаю, что эта работа еще не завершена. Но я хочу решить эту проблему. Жду вашей поддержки.

Думаю, вам следует использовать from rest_framework.viewsets import GenericViewSet

кроме того, вы не должны отправлять id клиента в параметрах запроса подобным образом.

вы можете использовать пользовательское действие с помощью декоратора @action(...) из rest_framework.decorators для обеспечения действия PUT без параметров запроса.

примерно так:

@action(detail=False, methods=['put'])
def me(self, request, *args, **kwargs):
    instance = request.user
    serializer = self.get_serializer(data=request.data, instance=instance, partial=True)
    serializer.is_valid(raise_exception=True)
    serializer.save()
    data = {"message": "your profile updated successfully"}
    return Response(data=data, status=status.HTTP_200_OK)

и ваш URL будет выглядеть следующим образом: user/me в urls.py

При таком подходе вам не нужно будет проверять пользователя, если он/она хочет обновить чужой профиль, больше никакого кода

Вернуться на верх