python 2.7 - User creation with unique constraint in Django Rest framework -
i researched in google, , have tried in lot of ways still not able right. here requirements:
- a 1 one field extending user model, has been achieved , new model called customer.
- now, new user 201 response returned not data serialized, date_of_birth coming in json format, want user in json response.
- if try add user username exists plays bad. trying try , except doesnt work. want response of 409 conflict sent if username exists. here userserializer.py:
-
from django.contrib.auth.models import user 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
here customer model:
from django.db import models 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
here customerserializer class:
from django.contrib.auth.models import user django.contrib.auth import get_user_model rest_framework import serializers, status rest_framework.response import response customers.models import customer 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 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()
and here view set customer:
from rest_framework import viewsets customers.models import customer customers.serializers import customerserializer api.permissions import isowneroradmin rest_framework import authentication, permissions, status 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 view create -----------------------------" serializer = self.get_serializer(data=request.data) # print serializer if serializer.is_valid(): # passes because here there no new objects created yet print "serializer valid ......" # self.pre_save(serializer.object) # user_data = serializer.validated_data.get("user") # print user_data self.object = serializer.create(serializer.validated_data) # creates user (triggering signal) instance , when saving userprofile, give 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)
so, create new customers data returned response , status 201 , if username exists, 409 or status code define , data drf should not complaint i.e; right says orderdict not contain pk if modify serializer.
thanks
edit 1
here updated serilizer custom exception:
from django.contrib.auth.models import user django.contrib.auth import get_user_model django.db import integrityerror rest_framework import serializers, status rest_framework.response import response rest_framework.exceptions import apiexception customers.models import customer 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 exception: # print exception # # print "customer --> %s " % customer # raise typeerror(exception) except integrityerror 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 there."
but still :
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) exists.
and test case follows:
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)
this because catching exceptions far broadly in create
method. in fact should never (regardless of whether use drf or not)
except exception exception: print exception # print "customer --> %s " % customer return customer
you should catch specific exceptions need catch. , shouldn't returning customer @ all. in case, examination of modelserializer tells 1 should catch typeerror. raised again caller handler.
except typeerror exception: print exception # print "customer --> %s " % customer raise typeerror(exception)
now should want according comments, not try raising custom error.
from rest_framework.exceptions import apiexception django.utils.encoding import force_text
class custom409(apiexception): status_code = status.http_409_conflict default_detail = 'a conflict occurred'
and then
except intergrityerror ext: print exception # print "customer --> %s " % customer raise custom409(ext)
Comments
Post a Comment