Как просмотреть профиль аутентифицированного пользователя в Django Rest Framework, используя токен
Я изучаю DRF и создаю простое приложение DRF, которое позволяет пользователю войти в систему, просмотреть профиль и обновить его. Я использую модель Django по умолчанию User и использую Knox для Token Authentication (если это можно сделать проще, используя Django Rest Authentication, пожалуйста, дайте мне знать, а также расскажите мне процедуру).
Я успешно создал API для регистрации и входа пользователя, который работает нормально, но я застрял на показе профиля аутентифицированному пользователю через токен.
У меня есть только одна модель Details, которая служит для хранения информации о профиле пользователя. У меня есть LoginSerializer, которая подключена к Login API и MainUserSerializer & UserSerializer, обе из которых подключены к User API (который действует для отображения информации о профиле на фронтенде).
Я много пробовал, искал везде, но все они показывают, как аутентифицировать пользователя с токеном через url (что-то вроде использования curl https://localhost:8000/api/user... и т.д.), postman, что-то вроде команды http post -a... в терминале и другие способы, но я не хочу тестировать или реализовывать эти способы. Мне нужно что-то, что если я открою url профиля пользователя после входа в систему с помощью ссылки localhost:8000/user, то на бэкенде это должно выглядеть так, как указано здесь введите описание ссылки здесь:
import requests
url = 'http://127.0.0.1:8000/hello/'
headers = {'Authorization': 'Token 9054f7aa9305e012b3c2300408c3dfdf390fcddf'}
r = requests.get(url, headers=headers)
Я очень старался, но мне не удается успешно перейти на страницу подробностей, аутентифицировав пользователя с помощью токена.
Мой models.py - это:
from django.db import models
# Create your models here.
from django.contrib.auth.models import User
class Detail(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
file = models.FileField(verbose_name="CSV File", upload_to='csv_files')
file_desc = models.TextField("CSV File Description")
def __str__(self):
return ("{} ({} {})".format(self.user.email, self.user.first_name, self.user.last_name))
def __unicode__(self):
return (self.file_desc)
Мой serializers.py - это:
from django.contrib.auth import authenticate
from django.contrib.auth.models import User
from .models import Detail
from rest_framework import serializers
class MainUserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('email',)
class UserSerializer(serializers.ModelSerializer):
usr = MainUserSerializer()
class Meta:
model = Detail
fields = ['usr', 'file', 'file_desc']
class LoginSerializer(serializers.Serializer):
email = serializers.EmailField()
password = serializers.CharField()
def validate(self, data):
user = authenticate(**{'username': data['email'], 'password': data['password']})
if user and user.is_active:
return user
raise serializers.ValidationError('Incorrect Credentials Passed.')
Мой views.py - это:
import requests
from rest_framework import permissions
from knox.models import AuthToken
from .serializers import UserSerializer, LoginSerializer
from django.shortcuts import redirect
from rest_framework.renderers import TemplateHTMLRenderer
from rest_framework.views import APIView
from django.urls import reverse
from django.http import HttpResponseRedirect
class LoginAPIHTML(APIView):
renderer_classes = [TemplateHTMLRenderer]
template_name = 'accounts/login.html'
def get(self, request):
serializer = LoginSerializer()
return Response({'serializer': serializer})
def post(self, request):
serializer = LoginSerializer(data=request.data)
if not serializer.is_valid():
return Response({'serializer': serializer})
user = serializer.validated_data
url = 'http://' + str(request.get_host()) + str(reverse('user', args=None))
headers = {
'Authorization': 'Token ' + str(AuthToken.objects.create(user)[1])
}
r = requests.get(url, headers=headers, format='json')
return HttpResponseRedirect(r)
Мой urls.py - это:
from django.urls import path, include
from .views import LoginAPIHTML
urlpatterns = [
path('api/v1/', include('knox.urls')),
path('login', LoginAPIHTML.as_view(), name='login'),
path('user', UserAPI.as_view(), name='user'),
]
и ниже мой settings.py:
INSTALLED_APPS = [
'accounts',
'rest_framework',
'rest_framework.authtoken',
'knox',
...
]
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'knox.auth.TokenAuthentication',
]
}
REST_AUTH_TOKEN_MODEL = 'knox.models.AuthToken'
REST_AUTH_TOKEN_CREATOR = 'project.apps.accounts.utils.create_knox_token'
Когда я ввожу правильные учетные данные в Login API в localhost:8000/login, то вместо перенаправления на страницу подробностей в localhost:8000/user я получаю следующую ошибку:
TypeError at /login
quote_from_bytes() expected bytes
Request Method: POST
Request URL: http://127.0.0.1:8000/login
Django Version: 4.0.3
Exception Type: TypeError
Exception Value:
quote_from_bytes() expected bytes
Traceback Switch to copy-and-paste view
C:\Users\Khubaib Khawar\AppData\Local\Programs\Python\Python310\lib\site-packages\django\core\handlers\exception.py, line 55, in inner
response = get_response(request) …
Local vars
C:\Users\Khubaib Khawar\AppData\Local\Programs\Python\Python310\lib\site-packages\django\core\handlers\base.py, line 197, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs) …
Local vars
C:\Users\Khubaib Khawar\AppData\Local\Programs\Python\Python310\lib\site-packages\django\views\decorators\csrf.py, line 54, in wrapped_view
return view_func(*args, **kwargs) …
Local vars
C:\Users\Khubaib Khawar\AppData\Local\Programs\Python\Python310\lib\site-packages\django\views\generic\base.py, line 84, in view
return self.dispatch(request, *args, **kwargs) …
Local vars
C:\Users\Khubaib Khawar\AppData\Local\Programs\Python\Python310\lib\site-packages\rest_framework\views.py, line 509, in dispatch
response = self.handle_exception(exc) …
Local vars
C:\Users\Khubaib Khawar\AppData\Local\Programs\Python\Python310\lib\site-packages\rest_framework\views.py, line 469, in handle_exception
self.raise_uncaught_exception(exc) …
Local vars
C:\Users\Khubaib Khawar\AppData\Local\Programs\Python\Python310\lib\site-packages\rest_framework\views.py, line 480, in raise_uncaught_exception
raise exc …
Local vars
C:\Users\Khubaib Khawar\AppData\Local\Programs\Python\Python310\lib\site-packages\rest_framework\views.py, line 506, in dispatch
response = handler(request, *args, **kwargs) …
Local vars
C:\Users\Khubaib Khawar\Downloads\Meistery\Round2\backend_dev_trial_ass_r2\accounts\views.py, line 202, in post
return HttpResponseRedirect(r) …
Local vars
C:\Users\Khubaib Khawar\AppData\Local\Programs\Python\Python310\lib\site-packages\django\http\response.py, line 538, in __init__
self["Location"] = iri_to_uri(redirect_to) …
Local vars
C:\Users\Khubaib Khawar\AppData\Local\Programs\Python\Python310\lib\site-packages\django\utils\encoding.py, line 139, in iri_to_uri
return quote(iri, safe="/#%[]=:;$&()+,!?*@'~") …
Local vars
C:\Users\Khubaib Khawar\AppData\Local\Programs\Python\Python310\lib\urllib\parse.py, line 870, in quote
return quote_from_bytes(string, safe) …
Local vars
C:\Users\Khubaib Khawar\AppData\Local\Programs\Python\Python310\lib\urllib\parse.py, line 895, in quote_from_bytes
raise TypeError("quote_from_bytes() expected bytes") …
Local vars
Я сыт этим по горло. Я буду очень признателен, если кто-нибудь поможет мне настроить это либо с помощью Knox, либо с помощью Django Rest Authentication. Заранее спасибо.
Это должно помочь:
https://studygyaan.com/django/django-rest-framework-tutorial-register-login-logout
Я использую это как руководство в любое время, когда использую Knox с drf.
Просмотр журналов ошибок, которые вы опубликовали:
Local vars C:\Users\Khubaib Khawar\Downloads\Meistery\Round2\backend_dev_trial_ass_r2\accounts\views.py, line 202, in post return HttpResponseRedirect(r) …
HttpResponseRedirect ожидает url или конечную точку, на которую нужно перенаправить запрос.
Но переменная r возвращает ответ от запроса GET, сделанного по адресу:
r = requests.get(url, headers=headers, format='json')
отсюда и ошибка:
raise TypeError("quote_from_bytes() expected bytes") …
Я думаю, что это похоже на :
TypeError: quote_from_bytes() ожидал байт после перенаправления