Django 2.1 令牌匹配查询不存在

Posted

技术标签:

【中文标题】Django 2.1 令牌匹配查询不存在【英文标题】:Django 2.1 Token matching query does not exist 【发布时间】:2019-08-28 14:28:37 【问题描述】:

我一直在尝试使用 rest_framework.authtoken 在 Django 中实现用户身份验证,就像在 this guide 中一样。我的测试用例测试了用户登录时可能出现的一系列不同的错误,在将访问令牌引入代码之前可以正常工作。

由于某种原因,当我添加对 Http 响应中返回的令牌的检查时,我收到错误:

rest_framework.authtoken.models.Token.DoesNotExist: Token matching query does not exist.

我已经添加了检查令牌所需的所有相关导入,所以 在最近的 django 版本之一中是否有一个函数被重新定位到不同的库?什么可能导致问题?

test.py

from django.urls import reverse 
from rest_framework.test import APITestCase
from django.contrib.auth.models import User
from rest_framework import status
from rest_framework.authtoken.models import Token


class AccountsTest(APITestCase):
    def setUp(self):
        # We want to go ahead and originally create a user. 
        self.test_user = User.objects.create_user('testuser', 'test@example.com', 'testpassword')
        print('test user:' + str(self.test_user))

        # URL for creating an account.
        self.create_url = reverse('account-create')

    def test_create_user(self):
        """
        Ensure we can create a new user and a valid token is created with it.
        """
        data = 
                'username': 'foobar',
                'email': 'foobar@example.com',
                'password': 'somepassword'
                

        response = self.client.post(self.create_url , data, format='json')
        user = User.objects.latest('id')

        token = Token.objects.get(user=user)
        self.assertEqual(response.data['token'], token.key)

views.py

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from accounts.serializers import UserSerializer
from django.contrib.auth.models import User
from rest_framework.authtoken.models import Token

class UserCreate(APIView):
    """ 
    Creates the user. 
    """

    def post(self, request, format='json'):
        serializer = UserSerializer(data=request.data)
        if serializer.is_valid():
            user = serializer.save()
            if user:
                token = Token.objects.create(user=user)
                json = serializer.data
                json['token'] = token.key
                return Response(json, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

settings.py

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    #third party
    'rest_framework',
    'rest_framework.authtoken',

REST_FRAMEWORK = 
    'DEFAULT_AUTHENTICATION_CLASSES': (
    'rest_framework.authentication.TokenAuthentication',
    ),
    'DEFAULT_PERMISSION_CLASSES': (
    'rest_framework.permissions.IsAuthenticatedOrReadOnly',
    ),

【问题讨论】:

user实例创建成功了吗,这个测试通过self.assertEqual(response.status_code, status.HTTP_201_CREATED) @HariHaraSudhan 不,它以AssertionError: 401 != 201 失败。由于某种原因,令牌身份验证无法正常工作,但在添加令牌身份验证之前所有测试都在工作。 @HariHaraSudhan 实际上,当我删除 'DEFAULT_PERMISSION_CLASSES': ( 'rest_framework.permissions.IsAuthenticatedOrReadOnly', ), 时测试通过了。如何让身份验证与权限一起工作。 【参考方案1】:

由于您的设置文件具有以下权限类,它将适用于所有扩展 APIView 的视图

'DEFAULT_PERMISSION_CLASSES': ( 'rest_framework.permissions.IsAuthenticatedOrReadOnly', )

所以设置default config as same.,通过在APIView 中设置permission_classes 属性来覆盖它,如下所示。

from rest_framework.permissions import AllowAny
class UserCreate(APIView):
     permission_classes = (AllowAny,)

【讨论】:

【参考方案2】:

在我的例子中,我能够使用.get_or_create 来传递错误,而不仅仅是.get

【讨论】:

【参考方案3】:

我重构了你的代码,它现在可以工作了。

class AccountsTest(APITestCase):
    def setUp(self):
        self.User = get_user_model()
        self.user = self.User.objects.create_user(
            email='first@user.com',
            password='foo',
            name='Adam',
            lastname='First',
        )
        print('created test user:' + str(self.user))

    def test_create_and_login_user(self):
        """
        Тестируем:
        1) Создание юзера
        2) Авторизацию
        3) Сверяем токены
        """
        create_url = reverse('create_user')
        login_url = reverse('login')

        # ТЕСТ-1: создаем пользователя
        create_data = 
            'email': 'foobar@example.com',
            'password': 'somepassword',
            'name': 'Adam',
            'lastname': 'First',
        
        response = self.client.post(create_url, create_data, format='json')
        self.assertEqual(status.HTTP_201_CREATED, response.status_code)

        # ТЕСТ-2: авторизовываемся чтобы server создал токен для клиента
        login_data = 
            'email': 'foobar@example.com',
            'password': 'somepassword',
        
        # после авторизации забираем ответ где хранится токен
        response = self.client.post(login_url, login_data, format='json')
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertIn('auth_token', response.data)
        # self.assertTrue(False, msg=response.data)

        # ТЕСТ-3: получаем id последнего зарегистрированного
        # пользователя и сверяем с тем что был в response
        user = self.User.objects.latest('id')
        # получаем его токен
        token = Token.objects.get(user=user)
        self.assertEqual(response.data['auth_token'], token.key)

【讨论】:

以上是关于Django 2.1 令牌匹配查询不存在的主要内容,如果未能解决你的问题,请参考以下文章

Django:SocialApp 匹配查询不存在

匹配查询不存在 django V3.2.9

ContentType 匹配查询不存在。 django=3.0.7

对 Django 用户匹配查询不存在消息感到沮丧

django admin - 匹配的查询不存在

Django REST EmailAddress 匹配查询不存在