视图有 IsAdminUser 限制。我也在使用令牌身份验证。
这是观点:
class UserRegister(generics.CreateAPIView):
permission_classes = [IsAdminUser]
queryset = User.objects.all()
serializer_class = RegisterSerializer
这是模型和模型管理器:
class UserManager(BaseUserManager):
def create_superuser(
self,
name: str,
email: str,
number: str,
password: Optional[str] = None,
) -> "User":
return self.create_user(name, email, number, password, True, True)
def create_staff(
self,
name: str,
email: str,
number: str,
password: Optional[str] = None,
) -> "User":
return self.create_user(name, email, number, password, True)
def create_user(
self,
name: str,
email: str,
number: str,
password: Optional[str] = None,
is_staff: bool = False,
is_superuser: bool = False,
) -> "User":
user = User(
name=name,
email=self.normalize_email(email),
number=number,
is_staff=is_staff,
is_superuser=is_superuser,
)
user.set_password(password)
user.save(using=self._db)
token = Token.objects.create(user=user)
return user
class User(AbstractBaseUser, PermissionsMixin):
name = models.CharField(max_length=50, unique=True)
email = models.EmailField(max_length=250, unique=True)
date = models.DateTimeField("Date", auto_now=True)
number = models.CharField(max_length=100, default="")
is_superuser = models.BooleanField(default=False)
is_staff = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
objects = UserManager()
USERNAME_FIELD = "name"
REQUIRED_FIELDS = ["email", "number", "password"]
def set_password(self, password: Optional[str] = None) -> Any:
if password:
self.password = password
else:
self.password = ""
return self.password
def __str__(self) -> str:
return f"{self.name} ({self.email}) {self.number} {self.password}"
这是我正在使用的序列化程序:
class RegisterSerializer(serializers.ModelSerializer):
repeat_password = serializers.CharField(
write_only=True, style={"input_type": "password"}
)
class Meta:
model = User
fields = ("name", "email", "number", "password", "repeat_password", "is_staff")
extra_kwargs = {"password": {"write_only": True}}
def validate(self, attrs: dict) -> dict:
password = attrs.get("password")
repeat_password = attrs.get("repeat_password")
if password != repeat_password:
raise serializers.ValidationError("Passwords do not match.")
return attrs
def create(self, validated_password: Any) -> Any:
repeat_password = validated_password.pop("repeat_password")
return User.objects.create_user(**validated_password)
这是测试代码:
class TestSetUp(APITestCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.user_manager = UserManager()
def setUp(self):
self.register_url = reverse("user_urls:register")
self.register_user_data = {
"name": "TestUser",
"email": "[email protected]",
"number": "1213",
"password": "Test@123",
}
self.login_url = reverse("user_urls:login")
self.login_user_data = {
"name": "TestUser",
"password": "Test@123",
}
self.register_user_data_with_empty_password = {
"name": "TestUser",
"email": "[email protected]",
"number": "1213",
"password": "",
}
return super().setUp()
def create_staff(self):
self.user = self.user_manager.create_staff(**self.register_user_data)
try:
self.token = Token.objects.get(user=self.user)
except Token.DoesNotExist:
self.token = Token.objects.create(user=self.user)
def create_superuser(self):
self.user = self.user_manager.create_superuser(**self.register_user_data)
try:
self.token = Token.objects.get(user=self.user)
except Token.DoesNotExist:
self.token = Token.objects.create(user=self.user)
这个片段应该使用自定义模型 User 和 UserManager 创建一个用户,只有代码中指定的字段(姓名、电子邮件、号码、密码)
class TestViews(TestSetUp):
def test_register_with_no_data(self) -> None:
res = self.client.post(self.register_url)
self.assertEqual(res.status_code, 401)
def test_register_with_data(self) -> None:
User.objects.create_staff(**self.register_user_data)
res = self.client.post(self.register_url)
self.assertEqual(res.status_code, 201)
def test_user_cannot_login_with_invalid_credentials(self):
self.client.post(self.register_url,self.register_user_data, format='json')
res = self.client.post(
self.login_url, self.login_user_data, format="json")
self.assertEqual(res.status_code, 401)
def test_user_can_login_with_valid_credentials(self):
res = self.client.post(
self.register_url, self.login_user_data, format='json'
)
if res.status_code != 201:
raise ValueError(f"Registration failed with error: {res.data}")
name = res.data["name"]
password = res.data["password"]
user = User.objects.get(name=name, password=password)
user.is_verified = True
user.save()
response = self.client.post(
self.login_url, self.login_user_data, format="json")
self.assertEqual(response.status_code, 201)
这里我需要调用 TestSetUp 并为其创建一个普通用户,这受到视图中 IsAdminUser 限制的限制,这意味着只允许员工或超级用户的身份验证令牌创建一个新的普通用户。
每次我运行报道时,我都会收到 401 错误消息
ValueError: Registration failed with error: {'detail': ErrorDetail(string='Authentication credentials were not provided.', code='not_authenticated')}
这是错误的回溯日志:
reating test database for alias 'default'...
System check identified no issues (0 silenced).
..F.EF
======================================================================
ERROR: test_user_can_login_with_valid_credentials (user.tests.tests_views.TestViews.test_user_can_login_with_valid_credentials)
----------------------------------------------------------------------
Traceback (most recent call last):
File "C:\Users\Owner\Desktop\myapp\user\tests\tests_views.py", line 23, in test_user_can_login_with_valid_credentials
raise ValueError(f"Registration failed with error: {res.data}")
ValueError: Registration failed with error: {'detail': ErrorDetail(string='Authentication credentials were not provided.', code='not_authenticated')}
======================================================================
FAIL: test_register_with_data (user.tests.tests_views.TestViews.test_register_with_data)
----------------------------------------------------------------------
Traceback (most recent call last):
File "C:\Users\Owner\Desktop\myapp\user\tests\tests_views.py", line 13, in test_register_with_data
self.assertEqual(res.status_code, 201)
AssertionError: 401 != 201
======================================================================
FAIL: test_user_cannot_login_with_invalid_credentials (user.tests.tests_views.TestViews.test_user_cannot_login_with_invalid_credentials)
----------------------------------------------------------------------
Traceback (most recent call last):
File "C:\Users\Owner\Desktop\myapp\user\tests\tests_views.py", line 18, in test_user_cannot_login_with_invalid_credentials
self.assertEqual(res.status_code, 401)
AssertionError: 400 != 401
----------------------------------------------------------------------
Ran 6 tests in 0.045s
FAILED (failures=2, errors=1)
Destroying test database for alias 'default'...
我没有尝试太多,因为我不明白我应该做什么。
我查看了 DRF 测试文档,但找不到任何可以帮助我处理这个问题的东西,有人可以帮忙吗?
这也是我第一次在 StackOverflow 提问,所以如果我有什么不清楚的地方请告诉我。
我不确定这些网址是否有任何必要,所以我决定在底部添加:
app_name = "user_urls"
router = routers.SimpleRouter()
router.register(r"user", UserView)
urlpatterns = [
path(
"register/",
UserRegister.as_view(),
name="register",
),
path("login/", obtain_auth_token, name="login"),
path(
"logout/",
auth_views.LogoutView.as_view(),
name="logout",
),
]
urlpatterns += router.urls