我有一个看起来像这样的测试用例(重点是防止重复的用户配置文件):
def test_create_duplicate_profile(self):
new_user = models.User(
username='bobjones',
password=';alsdfkj;asoi'
)
new_user.save()
client = APIClient()
client.force_authenticate(new_user)
response = client.post(
path='/api/profiles/'
)
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
same_user = models.User.objects.get(
username='bobjones'
)
response = client.post(
path='/api/profiles/'
)
self.assertEqual(response.status_code, status.HTTP_409_CONFLICT)
client.logout()
这会导致错误(以及测试失败):
(.virtualenv) nbascoutingdotcom $ python manage.py test profiles
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
E..
======================================================================
ERROR: test_create_duplicate_profile (profiles.tests.test_api.ProfilesAPITest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/evanzamir/nbascoutingdotcom/.virtualenv/lib/python3.6/site-packages/django/db/backends/utils.py", line 65, in execute
return self.cursor.execute(sql, params)
File "/Users/evanzamir/nbascoutingdotcom/.virtualenv/lib/python3.6/site-packages/django/db/backends/sqlite3/base.py", line 328, in execute
return Database.Cursor.execute(self, query, params)
sqlite3.IntegrityError: UNIQUE constraint failed: profiles_profile.user_id
我的模型看起来像这样:
class Profile(TimestampModerated):
id = models.BigAutoField(primary_key=True, db_column='id', null=False)
uuid = models.UUIDField(db_index=True, default=uuid_lib.uuid4(), editable=False)
user = models.OneToOneField('auth.User', on_delete=models.CASCADE, related_name='profiles', blank=False,
unique=True)
bio = models.CharField(max_length=140, blank=True, null=True)
media_url = models.URLField(blank=True, null=True)
dob = models.DateField(blank=True, null=True)
class Meta:
verbose_name_plural = "profiles"
这是序列化器:
class ProfileSerializer(serializers.ModelSerializer):
user = serializers.CharField(source='user.username', read_only=True,
validators=[UniqueValidator(queryset=Profile.objects.all())])
email = serializers.CharField(source='user.email', read_only=True)
first = serializers.CharField(source='user.first_name', read_only=True)
last = serializers.CharField(source='user.last_name', read_only=True)
last_login = serializers.DateTimeField(source='user.last_login', read_only=True)
date_joined = serializers.DateTimeField(source='user.date_joined', read_only=True)
class Meta:
model = Profile
fields = ('id', 'created', 'moderation_code', 'user', 'updated', 'uuid', 'bio', 'email',
'first', 'last', 'last_login', 'media_url', 'dob', 'date_joined')
这是我的ViewSet:
class ProfileViewSet(viewsets.ModelViewSet):
"""
This viewsetomatically provides `list`, `create`, `retrieve`,
`update` and `destroy` actions.
"""
queryset = Profile.objects.all()
serializer_class = ProfileSerializer
authentication_classes = (SessionAuthentication,)
permission_classes = (permissions.AllowAny, IsOwnerOrReadOnly)
lookup_field = 'user'
def perform_create(self, serializer):
serializer.save(user=self.request.user)
我希望能够发回有效的HTTP状态代码(HTTP_40X_),但我似乎无法挂钩验证错误。我尝试在perform_create
方法中添加一些代码来引发ValidationError,但这对我不起作用。有什么建议吗?
答案 0 :(得分:1)
您必须挂钩ModelViewSet.create(...)
,其中创建并返回实际响应:
from rest_framework import status
from rest_framework.response import Response
def create(self, request, *args, **kwargs):
try:
return super(ProfileViewSet, self).create(request, *args, **kwargs):
except IntegrityError:
return Response(status=status.HTTP_409_CONFLICT)
对于更一般的项目范围方法,您可能还会阅读drf docs on custom exception handling。