【发布时间】:2017-03-27 07:35:41
【问题描述】:
我在 Google 上进行了研究,并尝试了很多方法,但仍然无法正确解决。以下是要求:
- 用于扩展用户模型的一对一字段,因此这已经实现,新模型称为客户。
- 现在,返回新的用户 201 响应,但并非所有数据都被序列化,只有 date_of_birth 以 json 格式出现,我什至希望用户也在该 json 响应中。
- 如果我尝试添加一个用户名已经存在的用户,它的效果会非常糟糕。我正在尝试尝试和除外,但它确实不起作用。如果用户名已经存在,我希望发送 409 冲突响应。 这是 UserSerializer.py:
-
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
这里是带有自定义异常的更新序列化程序:
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)
【问题讨论】:
-
现在这个问题变成了变色龙问题。
-
请重新阅读问题和评论。这是一个简单的测试用例,它尝试创建一个相似的用户两次,我期望状态码为 409。我在描述中也确实提到过。
标签: django python-2.7 django-rest-framework django-users django-1.8