开发者社区> 问答> 正文

为什么此API请求在Postman中工作,但在Django测试中引发错误?

我发布到我的API以通过Postman创建帐户

{
    "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, \*allback_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(\*rgs, \*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, \*rgs, \*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, \*rgs, \*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

这是我的manager.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)

我正在尝试以可重复的方式测试帐户创建。我希望测试的行为与Postman相同。为什么它们的行为不同,如何纠正该错误?

编辑:

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)

问题来源:stackoverflow

展开
收起
is大龙 2020-03-23 17:20:53 757 0
1 条回答
写回答
取消 提交回答
  • Are you using serializers? Could it be that your test method isn't actually pushing a JSON object? Although your string looks like a JSON object, Python needs to know that it is, indeed, a JSON object. It also looks like there may be some conflicting data within your test method. Your Postman post request is clean.

    Why are you using a test method anyway? If you use the Django Rest Framework, it has built-in API testing pages that will mimic Postman.

    EDIT: Try this:

    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)
    

    Make sure that you import your serializer into that view. Here you're declaring data as a Python object, and then passing it to the serializer that will convert it into a JSON object.

    我更改了用于帐户变量的过滤器,以检查是否已创建要提交的新用户(在我看来,这就是您要通过测试完成的工作)。

    实际上,昨晚我遇到了一个非常相似的问题,涉及到我正在研究的东西。

    回答来源:stackoverflow

    2020-03-23 17:21:02
    赞同 展开评论 打赏
问答排行榜
最热
最新

相关电子书

更多
CUDA MATH API 立即下载
API PLAYBOOK 立即下载
传统企业的“+互联网”-API服务在京东方的实践 立即下载