Check if user exists before creating new user djangorestframework

Viewed 4350

So far I have ->

serializer:

class UserSerializer(serializers.ModelSerializer):
    """Serializer to map the model instance into json format."""
    class Meta:
        """Map this serializer to a model and their fields."""
        model = User
        fields = ('id','username', 'mobile', 'password', 
                  'first_name','last_name','middle_name', 
                  'profile_pic','short_bio','friends_privacy',
                  'address_1','address_2','city',
                  'state','country','pin','verification_code',
                  'is_active','is_blocked','is_reported',
                  'date_created','date_modified')
        extra_kwargs = {'password': {'write_only': True}}
        read_only_fields = (
            'date_created', 'date_modified',
            'is_staff', 'is_superuser', 'is_active', 
            'date_joined',)
    def create(self, validated_data):
        mobile_ = validated_data['mobile']
        password_ = validated_data['password']
        username_ = validated_data['username']
        motp = self.context['request'].GET['motp']
        eotp = self.context['request'].GET['eotp']
        email_ = self.context['request'].GET['email']
        mflag = api.views.checkOTP_(mobile_,motp)
        eflag = api.views.checkOTP_(email_,eotp)
        if (mflag and eflag):
            user = User(
            username=username_,
            email =email_,
            password = make_password(password_),
            mobile = mobile_,
            )
            user.set_password(validated_data['password'])
            user.save()
            return user

view:

class UserView2(viewsets.ModelViewSet):
    queryset = User.objects.all()
    serializer_class = UserSerializer
    model = User

    def get_permissions(self):
        # allow non-authenticated user to create via POST
        return (AllowAny() if self.request.method == 'POST'
                else IsStaffOrTargetUser()),

I need to check for OTP of mobile and email and also if a user with same mobile or email already exists. If user already exists return a json response with error: already exists!. If user is new and OTP is wrong again raise an error. If user is new and OTP is correct, create an account.

Problem here is I tried to add the function to check for otp verification inside the def create of UserSerializer. But a serializer is supposed to return the model instance. But if you see the code, I am able to create a user only if OTP is right and user instance is returned. And there is no else.

So is there a better way to check for OTP in the view itself?

2 Answers

I don't agree with @Anjaneyulu there.. Serializer handles creation of objects as well.. hence the reason you have serializer.save().

But for the purpose of raising an exception for existing user with same OTP email/phone, you should write your own def validate_mobile(self, data) and def validate_email(self, data). DRF serializer will look for these methods in the class first and will run them if they exist. So your custom logic for checking those fields could be:

class UserSerializer(serializers.ModelSerializer):   
    def validate_mobile(self, value):
        ModelClass = self.Meta.model
        if ModelClass.objects.filter(mobile=value).exists():
            raise serializers.ValidationError('already exists')
        return value

    def validate_email_(self, value):
        ModelClass = self.Meta.model
        if ModelClass.objects.filter(email_=value).exists():
            raise serializers.ValidationError('already exists')
        return value
    class Meta:
        model = User
        fields = (
            ...,
        )

That is not the correct way of implementing it. Serializers are meant only for validation purposes. you should not implement the create method in serializer instead write it in ViewSet. Creating object is a business logic. It should always go in a ViewSet. Write a validation method to the serializer. I'm writing an example code below

serializers.py

 class UserSerializer(serializers.ModelSerializer):

    def validate_mobile(self, mobile_num):
         is_already_exists = Model.objects.filter(mobile=mobile_num).exists()
         if is_already_exists:
             raise serializers.ValidationError('already exists')
         return mobile_num

    class Meta:
        model = User
        fields = (
           'id','username', 'mobile', 'password',
           'first_name','last_name','middle_name','profile_pic',
           'short_bio','friends_privacy','address_1',
           'address_2','city','state','country',
           'pin','verification_code','is_active',
               'is_blocked','is_reported',
           'date_created','date_modified'
       )
       extra_kwargs = {'password': {'write_only': True}}
       read_only_fields = (
           'date_created', 'date_modified','is_staff',
           'is_superuser', 'is_active', 'date_joined',
       )

Viewsets.py(Business Logic)

class UserView2(viewsets.ModelViewSet):
    queryset = User.objects.all()
    serializer_class = UserSerializer

    def get_permissions(self):
        # allow non-authenticated user to create via POST
        return (AllowAny() if self.request.method == 'POST'
                else IsStaffOrTargetUser()),
    def create(self, serializer):
          # your logic goes here.
Related