Answer the question
In order to leave comments, you need to log in
What did I do wrong when I overridden the exception handler?
Error 500 Internal Server Error
renders.py
import json
from rest_framework.renderers import JSONRenderer
class UserJSONRenderer(JSONRenderer):
charset = 'utf-8'
def render(self, data, media_type=None, renderer_context=None):
errors = data.get('errors', None)
token = data.get('token', None)
if errors is not None:
return super(UserJSONRenderer, self).render(data)
if token is not None and isinstance(token, bytes):
data['token'] = token.decode('utf-8')
return json.dumps({
'user': data
})
from rest_framework import serializers
from .models import User
from django.contrib.auth import authenticate
class RegistrationSerializer(serializers.ModelSerializer):
""" Сериализация регистрации пользователя и создания нового. """
password = serializers.CharField(
max_length=128,
min_length=8,
write_only=True #Ставим True чтобы гарантировать, что поле может использоваться при обновлении или создании экземпляра, но не будет включено при сериализации представления.
)
# Клиентская сторона не должна иметь возможность отправлять токен вместе с
# запросом на регистрацию. Сделаем его доступным только на чтение.
token = serializers.CharField(max_length=255, read_only=True)
class Meta:
model = User
# Перечислить все поля, которые могут быть включены в запрос
# или ответ, включая поля, явно указанные выше.
fields = ['email', 'username', 'password', 'token']
def create(self, validated_data):
# Использовать метод create_user, который мы
# написали ранее, для создания нового пользователя.
return User.objects.create_user(**validated_data)
class LoginSerializer(serializers.Serializer):
email = serializers.CharField(max_length=255)
username = serializers.CharField(max_length=255, read_only=True)
password = serializers.CharField(max_length=128, write_only=True)
token = serializers.CharField(max_length=255, read_only=True)
def validate(self, data):
email = data.get('email', None)
password = data.get('password', None)
if email is None:
raise serializers.ValidationError(
'An email address is required to log in.'
)
if password is None:
raise serializers.ValidationError(
'A password is required to log in.'
)
user = authenticate(username=email, password=password)
if user is None:
raise serializers.ValidationError(
'A user with this email and password was not found.'
)
if not user.is_active:
raise serializers.ValidationError(
'This user has been deactivated.'
)
return {
'email': user.email,
'username': user.username,
'token': user.token
}
class UserSerializer(serializers.ModelSerializer):
""" Ощуществляет сериализацию и десериализацию объектов User. """
password = serializers.CharField(
max_length=128,
min_length=8,
write_only=True
)
class Meta:
model = User
fields = ('email', 'username', 'password', 'token',)
read_only_fields = ('token',)
def update(self, instance, validated_data):
""" Выполняет обновление User. """
password = validated_data.pop('password', None)
for key, value in validated_data.items():
setattr(instance, key, value) #(setattr) - Добавляет объекту указанный атрибут. (instance - Объект, который следует дополнить атрибутом, key - Строка с именем атрибута, value - Произвольное значение атрибута. )
if password is not None:
instance.set_password(password)
instance.save()
return instance
from django.shortcuts import render
from rest_framework import status
from rest_framework.generics import RetrieveUpdateAPIView
from rest_framework.permissions import AllowAny, IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView
from .renderers import UserJSONRenderer
from .serializers import (LoginSerializer, RegistrationSerializer, UserSerializer,)
class RegistrationAPIView(APIView):
"""
Разрешить всем пользователям (аутентифицированным и нет) доступ к данному эндпоинту.
"""
permission_classes = (AllowAny,)
serializer_class = RegistrationSerializer
renderer_classes = (UserJSONRenderer,)
def post(self, request):
user = request.data
# Паттерн создания сериализатора, валидации и сохранения - довольно стандартный
serializer = self.serializer_class(data=user)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
class LoginAPIView(APIView):
permission_classes = (AllowAny,)
renderer_classes = (UserJSONRenderer,)
serializer_class = LoginSerializer
def post(self, request):
user = request.data
serializer = self.serializer_class(data=user)
serializer.is_valid(raise_exception=True)
return Response(serializer.data, status=status.HTTP_200_OK)
class UserRetrieveUpdateAPIView(RetrieveUpdateAPIView):
permission_classes = (IsAuthenticated,)
renderer_classes = (UserJSONRenderer,)
serializer_class = UserSerializer
def retrieve(self, request, *args, **kwargs):
serializer = self.serializer_class(request.user)
return Response(serializer.data, status=status.HTTP_200_OK)
def update(self, request, *args, **kwargs):
serializer_data = request.data.get('user', {})
serializer = self.serializer_class(
request.user, data=serializer_data, partial=True
)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data, status=status.HTTP_200_OK)
REST_FRAMEWORK = {
'EXCEPTION_HANDLER': 'json_auth_project.exceptions.core_exception_handler',
'NON_FIELD_ERRORS_KEY': 'error',
}
from rest_framework.views import exception_handler
def core_exception_handler(exc, context):
response = exception_handler(exc, context)
handlers = {
'ValidationError': _handle_generic_error
}
exception_class = exc.__class__.__name__
if exception_class in handlers:
return handlers[exception_class](exc, context, response)
return response
def _handle_generic_error(exc, context, response):
response.data = {
'errors': response.data
}
Answer the question
In order to leave comments, you need to log in
Didn't find what you were looking for?
Ask your questionAsk a Question
731 491 924 answers to any question