python - 为什么此 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, *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
这是我的managers.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 相同。为什么它们的行为不同,我该如何纠正这个错误?
编辑:
视图.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
序列化程序.py
class CreateAccountSerializer(serializers.ModelSerializer):
class Meta:
model = Account
fields = '__all__'
def create(self, validated_data):
return Account.objects.create_user(**validated_data)
解决方案
你在使用序列化器吗?可能是您的测试方法实际上并没有推送 JSON 对象吗?尽管您的字符串看起来像一个 JSON 对象,但 Python 需要知道它确实是一个 JSON 对象。看起来您的测试方法中可能存在一些冲突的数据。您的邮递员发帖请求是干净的。
你为什么要使用测试方法呢?如果你使用 Django Rest Framework,它有内置的 API 测试页面,可以模仿 Postman。
编辑:试试这个:
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 对象的序列化程序。
我更改了您用于帐户变量的过滤器,以检查您提交的新用户是否已创建(在我看来,这就是您试图通过测试完成的内容)。
实际上,昨晚我在做的事情上遇到了一个非常相似的问题。
推荐阅读
- javascript - 仅搜索按列分组的最后记录
- javascript - 在 iOS 13 及更低版本中,WKWebView 如何调用异步 Javascript 函数(即返回承诺的函数)?
- java - Java - 从覆盖的方法访问枚举的私有字段
- c++ - Arduino伺服和直流电机无法正常工作
- firebase-tools - firebase emulators:start 抱怨缺少 Java,但已安装
- dictionary - Ansible jinja 字典创建多个文件
- ios - CoreData 轻量级迁移崩溃,即使添加了映射模型
- java - 从wildfly +java中的类路径加载文件
- android - Android:LoadStateAdapter 不在 recyclerview 网格布局中居中
- angular - 如何修复Angular 10中组件AppComponent的模板中发生错误