【问题标题】:Password required Django REST API User Serializer PUT request需要密码 Django REST API 用户序列化器 PUT 请求
【发布时间】:2019-05-14 22:28:00
【问题描述】:

我的 Django Rest API 用户序列化程序中的一个问题是:发出 PUT 请求时,密码字段是必需的。在 POST 请求中这是有道理的,但对于 PUT 尤其是如果 PUT 由管理员执行,密码字段应该允许为空。

如何更改我的序列化程序,以便 POST 需要密码,但 PUT 为空?

class UserSerializer(serializers.ModelSerializer):
    """The UserSerializer"""
    gender = serializers.IntegerField(source='profile.gender', read_only=False)
    clinic = serializers.CharField(
        source='profile.clinic.code', read_only=False)
    title_prefix = serializers.CharField(
        source='profile.academic_title_prefix',
        allow_blank=True,
        read_only=False)
    title_suffix = serializers.CharField(
        source='profile.academic_title_suffix',
        allow_blank=True,
        read_only=False)

    email = serializers.EmailField(
        required=True,
        validators=[UniqueValidator(queryset=User.objects.all())])
    username = serializers.CharField(
        validators=[UniqueValidator(queryset=User.objects.all())])
    password = serializers.CharField(min_length=8, write_only=True)

    class Meta:
        model = User
        fields = ('id', 'url', 'username', 'first_name', 'last_name', 'gender',
                  'title_prefix', 'title_suffix', 'clinic', 'email',
                  'is_staff', 'is_superuser', 'date_joined', 'last_login',
                  'password')


    def create(self, validated_data):
        """Create and return a new user and its associated profile."""

        user = User.objects.create_user(
            validated_data['username'],
            validated_data['email'],
            validated_data['password'],
        )

        user.set_password(validated_data['password'])

        user.first_name = validated_data['first_name']
        user.last_name = validated_data['last_name']
        user.is_staff = validated_data['is_staff']
        user.is_superuser = validated_data['is_superuser']

        user.save()

        # create associated profile
        profile_data = validated_data.pop('profile')

        profile = Profile.objects.create(
            user=user,
            gender=profile_data['gender'],
            clinic=Clinic.objects.get(code=profile_data['clinic']['code']),
            academic_title_prefix=profile_data['academic_title_prefix'],
            academic_title_suffix=profile_data['academic_title_suffix'],
        )
        user.profile = profile

        return user

    def update(self, instance, validated_data):
        """Update and return a existing user and its associated profile."""

        instance.first_name = validated_data.get('first_name',
                                                 instance.first_name)
        instance.last_name = validated_data.get('last_name',
                                                instance.last_name)

        # Only Superuser can make Superusers
        if self.context['request'].user.is_superuser:
            instance.is_staff = validated_data.get('is_staff',
                                                   instance.is_staff)
            instance.is_superuser = validated_data.get('is_superuser',
                                                       instance.is_superuser)

        profile_data = validated_data.pop('profile')

        profile = Profile.objects.get(user=instance)
        profile.gender = profile_data['gender']
        profile.clinic = Clinic.objects.get(
            code=profile_data['clinic']['code'])
        profile.academic_title_prefix = profile_data['academic_title_prefix']
        profile.academic_title_suffix = profile_data['academic_title_suffix']
        profile.save()
        instance.profile = profile

        return instance

【问题讨论】:

  • 为 Post 和 Put 请求创建单独的序列化程序
  • 根据 REST 原则,PUT 应该包含整个对象。但是,PATCH 用于部分更新选定的字段,并且只允许包含需要更新的字段。所以我建议你改用 PATCH

标签: django django-rest-framework


【解决方案1】:

不是序列化器的问题。问题是 DRF 需要使用 PUT 方法的所有字段。不需要所有字段的方法是PATCH

您需要覆盖视图集中的更新方法:

def update(self, request, *args, **kwargs):
    partial = True # Here I change partial to True
    instance = self.get_object()
    serializer = self.get_serializer(instance, data=request.data, partial=partial)
    serializer.is_valid(raise_exception=True)
    self.perform_update(serializer)

    return Response(serializer.data)

【讨论】:

    【解决方案2】:

    如果您使用 PUT 来更新值并且只想对password 字段进行验证,那么您可以尝试对viewsetgeneric views 进行这样的操作:

    class UserSerializer(serializers.ModelSerializer):
        def __init__(self, *args, **kwargs):
            super(UserSerializer, self).__init__(*args, **kwargs)
            if self.context['request'].method == "PUT":
                self.fields.pop('password')
    
       # rest of the code
    

    【讨论】:

      猜你喜欢
      • 2015-11-10
      • 1970-01-01
      • 2018-08-06
      • 2023-03-10
      • 2020-02-01
      • 1970-01-01
      • 2020-04-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多