简体   繁体   English

使用Django API Rest Framework更新用户错误

[英]Update user error with Django API rest framework

I can`t update users because Django gives me this error in postman: 我无法更新用户,因为Django在邮递员中给了我这个错误:

AttributeError at /profesionales/
Got AttributeError when attempting to get a value for field `user` on serializer `ProfesionalesSerializer`.
The serializer field might be named incorrectly and not match any attribute or key on the `User` instance.
Original exception text was: 'User' object has no attribute 'user'.

Request Method: PUT
Request URL: http://127.0.0.1:8000/profesionales/
Django Version: 1.11.6
Python Executable: C:\Users\Ismael\AppData\Local\Programs\Python\Python36\python.exe
Python Version: 3.6.3

Here is my code: 这是我的代码:

view.py view.py

#Listar todos los profesionales o crear uno
#profesionales/
class ProfesionalesList(APIView):


    def get_object(self, pk):
        try:
            return User.objects.get(username=pk)
        except User.DoesNotExist:
            raise Http404

    def get(self, request ):
        usuarios = Profesionales.objects.all()
        usuarioSerializer = ProfesionalesSerializer(usuarios, many=True)
        return Response(usuarioSerializer.data)

    def post(self, request):
        profesionalSerializer = ProfesionalesSerializer(data=request.data)
        if profesionalSerializer.is_valid():
            profesionalSerializer.save()
            return Response(profesionalSerializer.data, status=status.HTTP_201_CREATED)
        else:
            return Response(profesionalSerializer.errors, status=status.HTTP_400_BAD_REQUEST)
    def put(self, request, *args, **kwargs):
        instance = self.get_object(request.data.get('user').get('username'))

        profesionalSerializer = ProfesionalesSerializer(instance, data=request.data)
        if profesionalSerializer.is_valid():
            profesionalSerializer.save()
            return Response(profesionalSerializer.data, status=status.HTTP_201_CREATED)
        else:
            return Response(profesionalSerializer.errors, status=status.HTTP_400_BAD_REQUEST)

serializers.py serializers.py

class UserSerializer(serializers.Serializer):

    username = serializers.CharField()
    first_name = serializers.CharField(allow_blank=True)
    last_name = serializers.CharField(allow_blank=True)
    email = serializers.CharField(allow_blank=True)

    class Meta:
        fields = ('username', 'first_name', 'last_name', 'email')

        def create(self, validated_data):
            user = User.objects.create(**validated_data)
            return user

class ProfesionalesSerializer(serializers.Serializer):

    user = UserSerializer()
    numColegiado = serializers.CharField(allow_blank=False)

    class Meta:
            fields = ('user', 'numColegiado')

    def create(self, validated_data):
        user_data = validated_data.pop('user')
        user = User.objects.create(**user_data)
        profesional = Profesionales.objects.create(user=user, **validated_data)

        return profesional

    def update(self, instance, validated_data):

        num_colegiado = validated_data.get('numColegiado')
        user_data = validated_data.pop('user')
        user = User.objects.get(**user_data)

        profesionales = user.profesionales

        if num_colegiado:
            profesionales.numColegiado = num_colegiado
            profesionales.save()
        return instance

model.py 模型

class Profesionales(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    dni = models.CharField(max_length=9, blank=True, default='')
    numColegiado = models.CharField(max_length=8, blank=True, default='')
    valoracionMedia = models.FloatField(blank=True, default=0)
    numVotos = models.IntegerField(blank=True, default=0)

    def __str__(self):
        return self.numColegiado

Ok, I have it - but to be honest, you should rethink your API design. 好的,我知道了-但老实说,您应该重新考虑API设计。

The problem is that - there is no problem -I mean from yout code I cannot reproduce the error. 问题是-没有问题-我的意思是您的代码无法重现该错误。 It is probably I assumed the User model - if you can paste the user model definition would be great (or if this is a standard django user - also mention that). 可能我假设用户模型-如果您可以粘贴用户模型定义,那就太好了(或者,如果这是标准的django用户-还要提一下)。

So firstly I would change the serializers to model serializers: 所以首先我将序列化器更改为模型序列化器:

serializers.py serializers.py

class UsernameValidator(object):

    def set_context(self, serializer_field):
        """
        This hook is called by the serializer instance,
        prior to the validation call being made.
        """
        # Determine the existing instance, if this is an update operation.
        self.instance = getattr(serializer_field.parent, 'instance', None)
        if not self.instance:
            # try to get user from profesionales:
            root_instance = getattr(serializer_field.root, 'instance', None)
            self.instance = getattr(root_instance, 'user', None)

    def __call__(self, value):
        if self.instance and User.objects.filter(username=value).exclude(id=self.instance.id).exists():
            raise ValidationError('Username already exists.')

        if not self.instance and User.objects.filter(username=value).exists():
            raise ValidationError('Username already exists.')


class UserSerializer(serializers.ModelSerializer):

    username = serializers.CharField(max_length=128, validators=[UsernameValidator()])

    class Meta:
        model = User
        fields = ('username', 'first_name', 'last_name', 'email')


class ProfesionalesSerializer(serializers.ModelSerializer):

    user = UserSerializer()
    numColegiado = serializers.CharField(allow_blank=False)

    class Meta:
        model = Profesionales
        fields = ('user', 'numColegiado')

    def create(self, validated_data):
        user_data = validated_data.pop('user')
        user = User.objects.create(**user_data)
        profesional = Profesionales.objects.create(user=user, **validated_data)
        return profesional

    def update(self, instance, validated_data):
        user_data = validated_data.pop('user')
        user = instance.user
        userSerializer = UserSerializer(user, data=user_data)
        if userSerializer.is_valid(raise_exception=True):
            userSerializer.save()

        num_colegiado = validated_data.get('numColegiado')
        if num_colegiado:
            instance.numColegiado = num_colegiado
            instance.save()
        return instance

As you can note - I've added the UsernameValidator which is pretty important for API to work properly 0- it basically search for existing user instance and check if username exists or not; 如您所知-我添加了UsernameValidator ,这对于API正常工作非常重要0-它基本上是搜索现有的用户实例并检查用户名是否存在;

I've also changed the update method - now it is using the UserSerializer explicite; 我还更改了更新方法-现在它使用的是UserSerializer显式; Also corrected some bugs - returning validated_data instead of instance and so on. 还纠正了一些错误-返回validated_data而不是实例 ,依此类推。

At the end views.py : 最后, views.py

class ProfesionalesList(APIView):

    def get_object(self, pk):
        try:
            return User.objects.get(username=pk)
        except User.DoesNotExist:
            raise Http404

    def get(self, request ):
        usuarios = Profesionales.objects.all()
        usuarioSerializer = ProfesionalesSerializer(usuarios, many=True)
        return Response(usuarioSerializer.data)

    def post(self, request):
        profesionalSerializer = ProfesionalesSerializer(data=request.data)
        if profesionalSerializer.is_valid(raise_exception=True):
            profesionalSerializer.save()
        return Response(profesionalSerializer.data, status=status.HTTP_201_CREATED)

    def put(self, request, *args, **kwargs):
        user = self.get_object(request.data.get('user').get('username'))
        profesionalSerializer = ProfesionalesSerializer(user.profesionales, data=request.data)
        if profesionalSerializer.is_valid(raise_exception=True):
            profesionalSerializer.save()
        return Response(profesionalSerializer.data, status=status.HTTP_200_OK)

I've shorten the code - using the raise_exception in is_valid method. 我已经缩短了代码-使用is_valid方法raise_exception。

Actually - sorry for not following the stackoverflow rules - and do not provide an answer for your actual problem - but I strongly believe that analyzing the example you can figure it out. 实际上-很抱歉没有遵循stackoverflow规则-并没有为您的实际问题提供答案-但我坚信分析示例可以解决问题。 If you have any more questions - please ask. 如果您还有其他问题-请询问。

On your class ProfesionalesSerializer , you have defined user as an instance of UserSerializer . 在类ProfesionalesSerializer ,已将user定义为UserSerializer的实例。 Instead, user should be a field. 而是, user应该是一个字段。 You can't use serializers as "fields". 您不能将序列化器用作“字段”。

Edit: Ignore this. 编辑:忽略此。 Turns out you can . 原来你可以 See here: http://www.django-rest-framework.org/api-guide/serializers/#dealing-with-nested-objects 参见此处: http : //www.django-rest-framework.org/api-guide/serializers/#dealing-with-nested-objects

(thanks to @opalczynski) (感谢@opalczynski)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM