我在Google上研究过这个问题,并尝试了很多方法,但仍然无法做到正确。以下是要求:
-
from django.contrib.auth.models import User
from rest_framework import serializers
class UserSerializer(serializers.HyperlinkedModelSerializer):
new_username = serializers.SerializerMethodField()
class Meta:
model = User
fields = ('url', 'pk', 'username', 'email', 'is_staff', 'new_username')
extra_kwargs = {
'username': {'validators': []},
}
def get_new_username(self, obj):
return obj.username
以下是客户模型:
from django.db import models
from django.contrib.auth.models import User
class Customer(models.Model):
user = models.OneToOneField(User, related_name="customer", on_delete=models.CASCADE)
date_of_birth = models.DateField(max_length=8)
def __unicode__(self):
return u'%s' % self.user.username
这是CustomerSerializer类:
from django.contrib.auth.models import User
from django.contrib.auth import get_user_model
from rest_framework import serializers, status
from rest_framework.response import Response
from customers.models import Customer
from api.serializers import UserSerializer
class CustomerSerializer(serializers.HyperlinkedModelSerializer):
user = UserSerializer()
class Meta:
model = Customer
fields = ('url', 'date_of_birth', 'user')
def create(self, validated_data):
print "coming inside serializer create"
user_data = validated_data.pop("user")
print user_data
try:
userinstance = User.objects.get_or_create(**user_data)[0]
print "user..."
print userinstance
print validated_data
customer = Customer.objects.create(user=userinstance, **validated_data)
print customer.user
return customer
except Exception as exception:
print exception
# print "customer --> %s " % customer
return customer
def update(self, instance, validated_data):
print "coming inside update"
user_data = validated_data.pop("user")
username = user_data.pop('username')
user = get_user_model().objects.get_or_create(username=username)[0]
user.username = username
user.email = user_data.get('email', user.email)
user.save()
# instance.user = user
instance.date_of_birth = validated_data.get('date_of_birth', instance.date_of_birth)
instance.save()
以下是客户的观点设置:
from rest_framework import viewsets
from customers.models import Customer
from customers.serializers import CustomerSerializer
from api.permissions import IsOwnerOrAdmin
from rest_framework import authentication, permissions, status
from rest_framework.response import Response
class CustomerViewSet(viewsets.ModelViewSet):
serializer_class = CustomerSerializer
queryset = Customer.objects.all()
authentication_classes = (authentication.TokenAuthentication,
authentication.SessionAuthentication,
authentication.SessionAuthentication, )
def get_permissions(self):
if self.action == 'list':
self.permission_classes = (permissions.IsAdminUser,)
elif self.action == 'create':
self.permission_classes = (permissions.AllowAny,)
return super(self.__class__, self).get_permissions()
def create(self, request, *args, **kwargs):
print "This is view create -----------------------------"
serializer = self.get_serializer(data=request.data)
# print serializer
if serializer.is_valid(): # It passes because here there are no new objects created yet
print "serializer is valid ......"
# self.pre_save(serializer.object)
# user_data = serializer.validated_data.get("user")
# print user_data
self.object = serializer.create(serializer.validated_data) # It creates the User (triggering the signal) instance and then when saving UserProfile, it give the integrity error
# self.post_save(self.object, created=True)
# headers = self.get_success_headers(serializer.data)
print 'coming here ....1'
print self.object
return Response(serializer.validated_data, status=status.HTTP_201_CREATED)
print 'coming here..'
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
所以,基本上我想创建新客户,其中所有数据都作为响应和状态201返回,如果用户名已经存在,那么我定义的409或状态代码以及DRF不应该抱怨的一些数据,即;现在它说如果修改序列化程序,OrderDict不包含PK。
由于
修改1
这是更新的serilizer,带有自定义异常:
from django.contrib.auth.models import User
from django.contrib.auth import get_user_model
from django.db import IntegrityError
from rest_framework import serializers, status
from rest_framework.response import Response
from rest_framework.exceptions import APIException
from customers.models import Customer
from api.serializers import UserSerializer
class CustomerSerializer(serializers.HyperlinkedModelSerializer):
user = UserSerializer()
class Meta:
model = Customer
fields = ('url', 'pk', 'date_of_birth', 'user')
def create(self, validated_data):
print "coming inside serializer create"
user_data = validated_data.pop("user")
print user_data
try:
userinstance = User.objects.create_user(**user_data)
print "user..."
print userinstance
print validated_data
customer = Customer.objects.create(user=userinstance, **validated_data)
print customer.user
return customer
# except TypeError as exception:
# print exception
# # print "customer --> %s " % customer
# raise TypeError(exception)
except IntegrityError as exception:
raise Custom409(exception)
def update(self, instance, validated_data):
print "coming inside update"
user_data = validated_data.pop("user")
username = user_data.pop('username')
user = get_user_model().objects.get_or_create(username=username)[0]
user.username = username
user.email = user_data.get('email', user.email)
user.save()
# instance.user = user
instance.date_of_birth = validated_data.get('date_of_birth', instance.date_of_birth)
instance.save()
return instance
class Custom409(APIException):
status_code = status.HTTP_409_CONFLICT
default_detail = "User already there."
但仍然得到:
Traceback (most recent call last):
File "/home/naveen/projects/gratis/customers/tests.py", line 37, in test_if_anyone_could_create_customers
format='json')
File "/home/naveen/.virtualenvs/gratis/local/lib/python2.7/site-packages/rest_framework/test.py", line 299, in post
path, data=data, format=format, content_type=content_type, **extra)
File "/home/naveen/.virtualenvs/gratis/local/lib/python2.7/site-packages/rest_framework/test.py", line 221, in post
return self.generic('POST', path, data, content_type, **extra)
File "/home/naveen/.virtualenvs/gratis/local/lib/python2.7/site-packages/django/test/client.py", line 379, in generic
return self.request(**r)
File "/home/naveen/.virtualenvs/gratis/local/lib/python2.7/site-packages/rest_framework/test.py", line 288, in request
return super(APIClient, self).request(**kwargs)
File "/home/naveen/.virtualenvs/gratis/local/lib/python2.7/site-packages/rest_framework/test.py", line 240, in request
request = super(APIRequestFactory, self).request(**kwargs)
File "/home/naveen/.virtualenvs/gratis/local/lib/python2.7/site-packages/django/test/client.py", line 466, in request
six.reraise(*exc_info)
File "/home/naveen/.virtualenvs/gratis/local/lib/python2.7/site-packages/django/core/handlers/base.py", line 132, in get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/naveen/.virtualenvs/gratis/local/lib/python2.7/site-packages/django/views/decorators/csrf.py", line 58, in wrapped_view
return view_func(*args, **kwargs)
File "/home/naveen/.virtualenvs/gratis/local/lib/python2.7/site-packages/rest_framework/viewsets.py", line 83, in view
return self.dispatch(request, *args, **kwargs)
File "/home/naveen/.virtualenvs/gratis/local/lib/python2.7/site-packages/rest_framework/views.py", line 477, in dispatch
response = self.handle_exception(exc)
File "/home/naveen/.virtualenvs/gratis/local/lib/python2.7/site-packages/rest_framework/views.py", line 437, in handle_exception
self.raise_uncaught_exception(exc)
File "/home/naveen/.virtualenvs/gratis/local/lib/python2.7/site-packages/rest_framework/views.py", line 448, in raise_uncaught_exception
raise exc
IntegrityError: duplicate key value violates unique constraint "auth_user_username_key"
DETAIL: Key (username)=(user2) already exists.
此外,测试案例如下:
def test_if_anyone_could_create_customers(self):
create_user = self.client.post('/api/customers/',
{'user':{'username': 'user2', 'email': 'user2@gmail.com'}, 'date_of_birth':"1982-10-20"},
format='json')
print create_user
self.assertEqual(create_user.status_code, 201)
create_user = self.client.post('/api/customers/',
{'user': {'username': 'user2', 'email': 'user2@gmail.com'},'date_of_birth': "1982-10-20"},
format='json')
print create_user
# no duplicates
user = User.objects.all()
print user
self.assertEqual(create_user.status_code, 409)
答案 0 :(得分:2)
这是因为您在create
方法中过于广泛地捕获异常。事实上,你永远不应该这样做(无论你是否使用DRF)
except Exception as exception:
print exception
# print "customer --> %s " % customer
return customer
您应该只捕获需要捕获的特定异常。而你根本不应该回归客户。在这种情况下,对ModelSerializer的检查告诉我们,你真正应该捕获的唯一一个是TypeError。即使是再次为调用者提出处理程序。
except TypeError as exception:
print exception
# print "customer --> %s " % customer
raise TypeError(exception)
现在你应该得到你想要的东西,但根据你的评论,你不是那么试着提出自定义错误。
来自rest_framework.exceptions的导入APIException 来自django.utils.encoding import force_text
class Custom409(APIException):
status_code = status.HTTP_409_CONFLICT
default_detail = 'A conflict occurred'
然后
except IntergrityError as ext:
print exception
# print "customer --> %s " % customer
raise Custom409(ext)
答案 1 :(得分:1)
您的代码正在提升IntegrityErorr
,因为您在创建个人资料时违反了唯一约束。
创建用户个人资料/客户实例时,您应该使用get_or_create
。这样的事情应该有效。
# CustomerSerializer
def create(self, validated_data):
"""...snip..."""
try:
userinstance = User.objects.get_or_create(**user_data)[0]
customer = Customer.objects.get_or_create(
user=userinstance, defaults=validated_data)[0]
return customer
except Exception as exception:
# custom validationerror
raise ConflictError({"user": "User already exists"})
答案 2 :(得分:0)
也许您应该尝试直接在视图中捕捉它:
views.py
library(dplyr)
library(tidyr)
d %>% mutate(name=strsplit(name,split="[|]")) %>%
group_by(id) %>%
unnest() %>%
mutate(score=strsplit(score,split="[|]")) %>%
unnest()
##Source: local data frame [15 x 3]
##Groups: id [4]
##
## id name score
## <dbl> <chr> <chr>
##1 22 c e
##2 22 e e
##3 565 m k
##4 565 m e
##5 565 q k
##6 565 q e
##7 893 w e
##8 893 w k
##9 893 w e
##10 415 w e
##11 415 w o
##12 415 s e
##13 415 s o
##14 415 e e
##15 415 e o
删除您在序列化程序中创建的逻辑。 DRF异常意味着在视图而非序列化器中使用。