0

I want to update the Model data using nested serializers via PATCH call in DRF.

I have custom User Model, Country, City, Detail Model. I have MainUserSerializer, CountrySerializer, CitySerializer and UserSerializer, and I have UserAPI view.

Below is my models.py:

class User(AbstractBaseUser, PermissionsMixin):
    username = models.CharField(max_length=254, null=True, blank=True)
    email = models.EmailField(max_length=254, unique=True)
    first_name = models.CharField(max_length=254, null=True, blank=True)
    last_name = models.CharField(max_length=254, null=True, blank=True)
    is_staff = models.BooleanField(default=False)
    is_superuser = models.BooleanField(default=False)
    is_active = models.BooleanField(default=True)
    last_login = models.DateTimeField(null=True, blank=True)
    date_joined = models.DateTimeField(auto_now_add=True)
    
    USERNAME_FIELD = 'email'
    EMAIL_FIELD = 'email'
    REQUIRED_FIELDS = []

    objects = UserManager()

    def get_absolute_url(self):
        return "/users/%i/" % (self.pk)


class Country(models.Model):
    name = models.CharField(max_length=100, default='c')

    def __str__(self):
        return ("{}".format(self.name))


class City(models.Model):
    name = models.CharField(max_length=100 ,default='c')
    country = models.ForeignKey(Country, on_delete=models.CASCADE)

    def __str__(self):
        return ("{} ({})".format(self.name, self.country.name))


class Detail(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    gender = models.CharField(max_length=20, default='g')
    age = models.IntegerField(default=0)
    country = models.IntegerField(default=1)
    city = models.IntegerField(default=1)

    def __str__(self):
        return ("{} ({} {})".format(self.user.email, self.user.first_name, self.user.last_name))

my serializers.py:

class MainUserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ('id', 'username', 'first_name', 'last_name', 'email')

    
class CitySerializer(serializers.ModelSerializer):
    class Meta:
        model = City
        fields = ('name',)


class CountrySerializer(serializers.ModelSerializer):
    city = CitySerializer()

    class Meta:
        model = Country
        fields = ('name', 'city')


class UserSerializer(serializers.ModelSerializer):
    usr = MainUserSerializer()
    country = CountrySerializer()
    city = CitySerializer()

    class Meta:
        model = Detail
        fields = ('usr', 'gender', 'age', 'country', 'city')

    def update(self, instance, validated_data):
        instance = super().update(instance, validated_data)
        
        instance.save()
            
        return instance

and my views.py is:

class UserAPI(generics.GenericAPIView):
    permission_classes = [AllowAny]
    serializer_class = UserSerializer

    def get(self, request, id):
        detail = Detail.objects.get(user=User.objects.get(pk=id))
        usr = User.objects.get(pk=id)
        
        data = {
            'id': usr.id,
            'username': usr.username,
            'first_name': usr.first_name,
            'last_name': usr.last_name,
            'email': usr.email,
            'gender': detail.gender,
            'age': detail.age,
            'country': detail.country,
            'city': detail.city

        }

        return Response(data)

    def patch(self, request, id):
        usr = User.objects.get(pk=id)     
        detail = Detail.objects.get(user=usr)
        serializer = self.get_serializer(detail, data=request.data, partial=True)
        print(request.POST)
        
        if serializer.is_valid():
            serializer.save()
            print("SUCCESS")
            return Response(code=200)

        return JsonResponse(data="wrong parameters", safe=False)

Error Details:

Error Name: AttributeError: 'NoneType' object has no attribute '_meta'

Full Error:

Traceback Switch to copy-and-paste view
C:\Users\Khubaib Khawar\AppData\Local\Programs\Python\Python310\lib\site-packages\django\core\handlers\exception.py, line 55, in inner
                response = get_response(request) …
Local vars
C:\Users\Khubaib Khawar\AppData\Local\Programs\Python\Python310\lib\site-packages\django\core\handlers\base.py, line 220, in _get_response
                response = response.render() …
Local vars
C:\Users\Khubaib Khawar\AppData\Local\Programs\Python\Python310\lib\site-packages\django\template\response.py, line 114, in render
            self.content = self.rendered_content …
Local vars
C:\Users\Khubaib Khawar\AppData\Local\Programs\Python\Python310\lib\site-packages\rest_framework\response.py, line 70, in rendered_content
        ret = renderer.render(self.data, accepted_media_type, context) …
Local vars
C:\Users\Khubaib Khawar\AppData\Local\Programs\Python\Python310\lib\site-packages\rest_framework\renderers.py, line 724, in render
        context = self.get_context(data, accepted_media_type, renderer_context) …
Local vars
C:\Users\Khubaib Khawar\AppData\Local\Programs\Python\Python310\lib\site-packages\rest_framework\renderers.py, line 657, in get_context
        raw_data_patch_form = self.get_raw_data_form(data, view, 'PATCH', request) …
Local vars
C:\Users\Khubaib Khawar\AppData\Local\Programs\Python\Python310\lib\site-packages\rest_framework\renderers.py, line 563, in get_raw_data_form
                data = serializer.data.copy() …
Local vars
C:\Users\Khubaib Khawar\AppData\Local\Programs\Python\Python310\lib\site-packages\rest_framework\serializers.py, line 555, in data
        ret = super().data …
Local vars
C:\Users\Khubaib Khawar\AppData\Local\Programs\Python\Python310\lib\site-packages\rest_framework\serializers.py, line 257, in data
                self._data = self.get_initial() …
Local vars
C:\Users\Khubaib Khawar\AppData\Local\Programs\Python\Python310\lib\site-packages\rest_framework\serializers.py, line 403, in get_initial
        return OrderedDict([ …
Local vars
C:\Users\Khubaib Khawar\AppData\Local\Programs\Python\Python310\lib\site-packages\rest_framework\serializers.py, line 404, in <listcomp>
            (field.field_name, field.get_initial()) …
Local vars
C:\Users\Khubaib Khawar\AppData\Local\Programs\Python\Python310\lib\site-packages\rest_framework\serializers.py, line 405, in get_initial
            for field in self.fields.values() …
Local vars
C:\Users\Khubaib Khawar\AppData\Local\Programs\Python\Python310\lib\site-packages\django\utils\functional.py, line 49, in __get__
        res = instance.__dict__[self.name] = self.func(instance) …
Local vars
C:\Users\Khubaib Khawar\AppData\Local\Programs\Python\Python310\lib\site-packages\rest_framework\serializers.py, line 356, in fields
        for key, value in self.get_fields().items(): …
Local vars
C:\Users\Khubaib Khawar\AppData\Local\Programs\Python\Python310\lib\site-packages\rest_framework\serializers.py, line 1051, in get_fields
        info = model_meta.get_field_info(model) …
Local vars
C:\Users\Khubaib Khawar\AppData\Local\Programs\Python\Python310\lib\site-packages\rest_framework\utils\model_meta.py, line 39, in get_field_info
    forward_relations = _get_forward_relationships(opts) …
Local vars
C:\Users\Khubaib Khawar\AppData\Local\Programs\Python\Python310\lib\site-packages\rest_framework\utils\model_meta.py, line 96, in _get_forward_relationships
                not field.remote_field.through._meta.auto_created …
Local vars

Anyone please guide me why I am getting this error.

Neha AK
  • 67
  • 1
  • 10

1 Answers1

0

You wrote usr instead of user in your serializer:

class UserSerializer(serializers.ModelSerializer):
    user = MainUserSerializer()  # Here
    country = CountrySerializer()
    city = CitySerializer()

    class Meta:
        model = Detail
        fields = ('user', 'gender', 'age', 'country', 'city')  # Here

    def update(self, instance, validated_data):
        instance = super().update(instance, validated_data)
        
        instance.save()
            
        return instance
Alain Bianchini
  • 3,883
  • 1
  • 7
  • 27
  • That I wrote on purpose to not to mix up things, you can see I have used the field name `'user'` as well and I have used instance with same name afterwards – Neha AK Apr 07 '22 at 18:45
  • @NehaAK If you only did it in the question that's fine (if it's only in the question correct it). But if you have done it also in the code, changing the name of the field in the ModelSerializer is an error. – Alain Bianchini Apr 07 '22 at 19:05
  • in `UserSerizlier`, I am making a nested serializer of `MainUserSerializer()` and assing it to a variable name called `usr`, so `usr` was not any field before, but I initialized it with nested serializer and then using it as field of parent serializer that is `UserSerializer`, please have a look at my code again and then tell if it is still wrong. – Neha AK Apr 07 '22 at 19:21
  • @NehaAK Excuse me but I don' t understand why you add a field called `usr`, when do you use that field and where its value come from? If you want to serialize the `user` field with `MainUserSerializer`, simply call the field `user`. Please try to name it `user` to see if the error persists – Alain Bianchini Apr 07 '22 at 19:40