dot64dot
dot64dot

Reputation: 561

Django Rest Framework: AttributeError: 'NoneType' object has no attribute '_meta' [for OneToOneField]

I need help with a POST request using Django rest framework.

I have a User model that inherits from AbstractBaseUser which has 2 fields: name and email.

Then I have a DojoMaster model that has a OneToOne relationship with the User model:

class DojoMaster(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)
    phone = models.BigIntegerField()
    country = models.ForeignKey(Country, on_delete=models.CASCADE)

I want to register the dojo master via an API so I created the following serializers:

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ('name', 'email', 'password')

class DojoMasterCreateSerializer(serializers.ModelSerializer):
    user = UserSerializer(required=True)

    class Meta:
        model = DojoMaster
        fields = ('user', 'phone', 'country')

    def create(self, validated_data):
        validated_data['country'] = Country.objects.get(
            country=validated_data['country'])
        user_data = validated_data.pop('user')
        user = UserSerializer.create(UserSerializer(), validated_data=user_data)
        subscriber, created = DojoMaster.objects.update_or_create(user=user,
                        phone  = validated_data.pop('phone'),
                        country = validated_data['country'])
        return subscriber

To call on these serializers, I created the following view:

class DojoMasterCreateView(generics.CreateAPIView):

    def post(self, request, format='json'):
        serializer = DojoMasterCreateSerializer(data=request.data)
        if serializer.is_valid(raise_exception=ValueError):
            serializer.create(validated_data=request.data)
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

For the body of the POST request I had the following:

{
    "user": {
        "name": "XYZ",
        "email": "[email protected]",
        "password": "8Xa,9Lv&"
    },
    "phone": 9696510,
    "country": "USA"
}

However, when I do that I get the following error:

Traceback (most recent call last):
File "C:\Users\app_dev\Envs\game_of_quarks\lib\site-packages\django\core\handlers\exception.py", line 41, in inner
    response = get_response(request)
File "C:\Users\app_dev\Envs\game_of_quarks\lib\site-packages\django\core\handlers\base.py", line 187, in _get_response
    response = self.process_exception_by_middleware(e, request)
File "C:\Users\app_dev\Envs\game_of_quarks\lib\site-packages\django\core\handlers\base.py", line 185, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "C:\Users\app_dev\Envs\game_of_quarks\lib\site-packages\django\views\decorators\csrf.py", line 58, in wrapped_view
    return view_func(*args, **kwargs)
File "C:\Users\app_dev\Envs\game_of_quarks\lib\site-packages\django\views\generic\base.py", line 68, in view
    return self.dispatch(request, *args, **kwargs)
File "C:\Users\app_dev\Envs\game_of_quarks\lib\site-packages\rest_framework\views.py", line 494, in dispatch
    response = self.handle_exception(exc)
File "C:\Users\app_dev\Envs\game_of_quarks\lib\site-packages\rest_framework\views.py", line 454, in handle_exception
    self.raise_uncaught_exception(exc)
File "C:\Users\app_dev\Envs\game_of_quarks\lib\site-packages\rest_framework\views.py", line 491, in dispatch
    response = handler(request, *args, **kwargs)
File "C:\Users\app_dev\development\GOQ\dojomaster_api\views.py", line 29, in post
    if serializer.is_valid(raise_exception=ValueError):
File "C:\Users\app_dev\Envs\game_of_quarks\lib\site-packages\rest_framework\serializers.py", line 236, in is_valid
    self._validated_data = self.run_validation(self.initial_data)
File "C:\Users\app_dev\Envs\game_of_quarks\lib\site-packages\rest_framework\serializers.py", line 435, in run_validation
    value = self.to_internal_value(data)
File "C:\Users\app_dev\Envs\game_of_quarks\lib\site-packages\rest_framework\serializers.py", line 465, in to_internal_value
    validated_value = field.run_validation(primitive_value)
File "C:\Users\app_dev\Envs\game_of_quarks\lib\site-packages\rest_framework\serializers.py", line 437, in run_validation
    self.run_validators(value)
File "C:\Users\app_dev\Envs\game_of_quarks\lib\site-packages\rest_framework\fields.py", line 533, in run_validators
    for validator in self.validators:
File "C:\Users\app_dev\Envs\game_of_quarks\lib\site-packages\rest_framework\fields.py", line 392, in validators
    self._validators = self.get_validators()
File "C:\Users\app_dev\Envs\game_of_quarks\lib\site-packages\rest_framework\serializers.py", line 1460, in get_validators
    self.get_unique_for_date_validators()
File "C:\Users\app_dev\Envs\game_of_quarks\lib\site-packages\rest_framework\serializers.py", line 1502, in get_unique_for_date_validators
    info = model_meta.get_field_info(self.Meta.model)
File "C:\Users\app_dev\Envs\game_of_quarks\lib\site-packages\rest_framework\utils\model_meta.py", line 39, in get_field_info
    forward_relations = _get_forward_relationships(opts)
File "C:\Users\app_dev\Envs\game_of_quarks\lib\site-packages\rest_framework\utils\model_meta.py", line 96, in _get_forward_relationships
    not field.remote_field.through._meta.auto_created
AttributeError: 'NoneType' object has no attribute '_meta'

I cannot figure out what the problem is. Help would be much appreciated.

Upvotes: 2

Views: 8989

Answers (1)

Aneesh R S
Aneesh R S

Reputation: 3827

serializer.is_valid method accepts keyword argument raise_exception. And its value should be true or false. By default it is false. If it is true, the exception will be auto triggered. change your serializer.is_valid(raise_exception=ValueError) to serializer.is_valid().

And also for saving the serializer you should call the save method not the create method

class DojoMasterCreateView(generics.CreateAPIView):

    def post(self, request, format='json'):
        serializer = DojoMasterCreateSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
    return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

or in simple form

class DojoMasterCreateView(generics.CreateAPIView):

    def post(self, request, format='json'):
        serializer = DojoMasterCreateSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        serializer.save()
    return Response(serializer.data, status=status.HTTP_201_CREATED)

And i have no idea what user = UserSerializer.create(UserSerializer(), validated_data=user_data) means or create method logic is doing. If you want to save the user data, then follow the code given beloe

class DojoMasterCreateSerializer(serializers.ModelSerializer):
    user = UserSerializer(required=True)

    class Meta:
        model = DojoMaster
        fields = ('user', 'phone', 'country')

    def create(self, validated_data):
        user_data = validated_data.pop('user')
        user = User.objects.create(**user_data)
        subscriber, created = DojoMaster.objects.update_or_create(user=user, **validated_data)
        return subscriber

And the json should contain the id of the country, like

{
    "user": {
        "name": "XYZ",
        "email": "[email protected]",
        "password": "8Xa,9Lv&"
    },
    "phone": 9696510,
    "country": 1
}

Upvotes: 2

Related Questions