Почему этот запрос API работает в Postman, но в тесте Django возникает ошибка? - PullRequest
1 голос
/ 15 марта 2020

Я отправляю сообщение в мой API для создания учетной записи Почтальона

{
    "email": "snifter@gmail.com",
    "display_name": "outrageous canteloupe",
    "password": "GramDaddyff!!5"
}

Это работает, и новая учетная запись регистрируется в базе данных.

Затем я пытаюсь сделать тот же запрос из теста Django.

class AccountAPITestCase(TestCase):

    def setUp(self):
        pass

    def test_create_account(self):
        c = Client()
        response = c.post('/accounts/', {
            "email": "snifter@gmail.com",
            "display_name": "outrageous canteloupe",
            "password": "GramDaddyff!!5",
        })
        account = Account.objects.get(display_name='big_ouch')
        self.assertTrue(account)

И я получаю следующую ошибку.

======================================================================
ERROR: test_create_account (accounts.tests.AccountAPITestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/mcm66103/Documents/python/photo-contest-BE/accounts/tests.py", line 28, in test_create_account
    "password": "use_in_migrationsDaddyff!!5",
  File "/Users/mcm66103/.envs/photo-contest-BE/lib/python3.7/site-packages/django/test/client.py", line 526, in post
    response = super().post(path, data=data, content_type=content_type, secure=secure, **extra)
  File "/Users/mcm66103/.envs/photo-contest-BE/lib/python3.7/site-packages/django/test/client.py", line 356, in post
    secure=secure, **extra)
  File "/Users/mcm66103/.envs/photo-contest-BE/lib/python3.7/site-packages/django/test/client.py", line 421, in generic
    return self.request(**r)
  File "/Users/mcm66103/.envs/photo-contest-BE/lib/python3.7/site-packages/django/test/client.py", line 496, in request
    raise exc_value
  File "/Users/mcm66103/.envs/photo-contest-BE/lib/python3.7/site-packages/django/core/handlers/exception.py", line 34, in inner
    response = get_response(request)
  File "/Users/mcm66103/.envs/photo-contest-BE/lib/python3.7/site-packages/django/core/handlers/base.py", line 115, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "/Users/mcm66103/.envs/photo-contest-BE/lib/python3.7/site-packages/django/core/handlers/base.py", line 113, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/Users/mcm66103/.envs/photo-contest-BE/lib/python3.7/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
    return view_func(*args, **kwargs)
  File "/Users/mcm66103/.envs/photo-contest-BE/lib/python3.7/site-packages/rest_framework/viewsets.py", line 114, in view
    return self.dispatch(request, *args, **kwargs)
  File "/Users/mcm66103/.envs/photo-contest-BE/lib/python3.7/site-packages/rest_framework/views.py", line 505, in dispatch
    response = self.handle_exception(exc)
  File "/Users/mcm66103/.envs/photo-contest-BE/lib/python3.7/site-packages/rest_framework/views.py", line 465, in handle_exception
    self.raise_uncaught_exception(exc)
  File "/Users/mcm66103/.envs/photo-contest-BE/lib/python3.7/site-packages/rest_framework/views.py", line 476, in raise_uncaught_exception
    raise exc
  File "/Users/mcm66103/.envs/photo-contest-BE/lib/python3.7/site-packages/rest_framework/views.py", line 502, in dispatch
    response = handler(request, *args, **kwargs)
  File "/Users/mcm66103/.envs/photo-contest-BE/lib/python3.7/site-packages/rest_framework/mixins.py", line 19, in create
    self.perform_create(serializer)
  File "/Users/mcm66103/.envs/photo-contest-BE/lib/python3.7/site-packages/rest_framework/mixins.py", line 24, in perform_create
    serializer.save()
  File "/Users/mcm66103/.envs/photo-contest-BE/lib/python3.7/site-packages/rest_framework/serializers.py", line 212, in save
    self.instance = self.create(validated_data)
  File "/Users/mcm66103/Documents/python/photo-contest-BE/accounts/serializers.py", line 19, in create
    return Account.objects.create_user(**validated_data)
  File "/Users/mcm66103/Documents/python/photo-contest-BE/accounts/managers.py", line 17, in create_user
    user = self.model(email=email, **extra_fields)
  File "/Users/mcm66103/.envs/photo-contest-BE/lib/python3.7/site-packages/django/db/models/base.py", line 495, in __init__
    _setattr(self, prop, kwargs[prop])
  File "/Users/mcm66103/.envs/photo-contest-BE/lib/python3.7/site-packages/django/db/models/fields/related_descriptors.py", line 546, in __set__
    % self._get_set_deprecation_msg_params(),
TypeError: Direct assignment to the forward side of a many-to-many set is prohibited. Use groups.set() instead.

Вот мой пользователь models.py.

from accounts.managers import AccountManager


class Account(AbstractUser):
    username = None
    display_name = models.CharField(max_length=32)
    email = models.EmailField(_('email address'), unique=True)

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = []

    objects = AccountManager()

    def __str__(self):
        return self.email

Вот мои менеджеры.py.

from django.contrib.auth.base_user import BaseUserManager
from django.utils.translation import ugettext_lazy as _


class AccountManager(BaseUserManager):
    """
    Custom user model manager where email is the unique identifiers
    for authentication instead of usernames.
    """
    def create_user(self, email, password, **extra_fields):
        """
        Create and save a User with the given email and password.
        """
        if not email:
            raise ValueError(_('The Email must be set'))
        email = self.normalize_email(email)
        user = self.model(email=email, **extra_fields)
        user.set_password(password)
        user.save()
        return user

    def create_superuser(self, email, password, **extra_fields):
        """
        Create and save a SuperUser with the given email and password.
        """
        extra_fields.setdefault('is_staff', True)
        extra_fields.setdefault('is_superuser', True)
        extra_fields.setdefault('is_active', True)

        if extra_fields.get('is_staff') is not True:
            raise ValueError(_('Superuser must have is_staff=True.'))
        if extra_fields.get('is_superuser') is not True:
            raise ValueError(_('Superuser must have is_superuser=True.'))
        return self.create_user(email, password, **extra_fields)

Я пытаюсь проверить создание аккаунта повторяющимся способом. Я ожидаю, что тест будет вести себя так же, как Почтальон. Почему они ведут себя по-разному, и как я могу исправить эту ошибку?

РЕДАКТИРОВАТЬ:

views.py

class AccountViewSet(viewsets.ModelViewSet):
    serializer_class = None
    queryset = Account.objects.all()

    def get_serializer_class(self):
        if self.action == 'list':
            return AccountSerializer
        if self.action == 'create':
            return CreateAccountSerializer

serializers.py

class CreateAccountSerializer(serializers.ModelSerializer):
    class Meta:
        model = Account
        fields = '__all__'

    def create(self, validated_data):
        return Account.objects.create_user(**validated_data)

1 Ответ

0 голосов
/ 15 марта 2020

Вы используете сериализаторы? Может ли быть так, что ваш тестовый метод на самом деле не выдвигает объект JSON? Хотя ваша строка выглядит как объект JSON, Python необходимо знать, что это действительно объект JSON. Похоже, что в вашем методе тестирования могут быть некоторые противоречивые данные. Ваш почтовый запрос почтальона чистый.

Почему вы все равно используете метод тестирования? Если вы используете Django Rest Framework, он имеет встроенные страницы тестирования API, которые будут имитировать c Почтальон.

РЕДАКТИРОВАТЬ: Попробуйте это:

class AccountAPITestCase(TestCase):

    def setUp(self):
        pass

    def test_create_account(self):

        data = {
            "email": "snifter@gmail.com",
            "display_name": "outrageous canteloupe",
            "password": "GramDaddyff!!5",            
        }
        serializer = CreateAccountSerializer(data=data)
        if serializer.is_valid:
        new_user = serializer.validated_data

        c = Client()
        response = c.post('/accounts/', new_user)

        account = Account.objects.get(display_name=data.display_name)
        self.assertTrue(account)

Убедитесь, что вы импортируете ваш сериализатор в это представление. Здесь вы объявляете данные как объект Python, а затем передаете их сериализатору, который преобразует их в объект JSON.

Я изменил фильтр, который вы используете для переменной учетной записи, на проверьте, был ли создан новый пользователь, которого вы отправляете (мне показалось, что вы пытаетесь выполнить sh с помощью своего теста).

У меня на самом деле только что была похожая проблема в прошлом ночь с чем-то, над чем я работал.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...