加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Python > 正文

Django Rest框架序列化器和视图

发布时间:2020-12-20 11:52:04 所属栏目:Python 来源:网络整理
导读:我很困惑如何在DRF中的序列化器和视图中实现方法: 我有一个扩展AbstractBaseUser的帐户模型.视图集如下所示: class AccountViewSet(viewsets.ModelViewSet): lookup_field = 'username' queryset = Account.objects.all() serializer_class = AccountSeria
我很困惑如何在DRF中的序列化器和视图中实现方法:

我有一个扩展AbstractBaseUser的帐户模型.视图集如下所示:

class AccountViewSet(viewsets.ModelViewSet):
    lookup_field = 'username'
    queryset = Account.objects.all()
    serializer_class = AccountSerializer

    def get_permissions(self):
        if self.request.method in permissions.SAFE_METHODS:
            return (permissions.AllowAny(),TokenHasReadWriteScope())

        if self.request.method == 'POST':
            return (permissions.AllowAny(),TokenHasReadWriteScope())

        return (permissions.IsAuthenticated(),IsAccountOwner(),TokenHasReadWriteScope())

    def create(self,request):
        serializer = self.serializer_class(data=request.data)

        if serializer.is_valid():
            Account.objects.create_user(**serializer.validated_data)

            return Response(serializer.validated_data,status=status.HTTP_201_CREATED)
        return Response({
            'status': 'Bad request','message': 'Account could not be created with received data.'
        },status=status.HTTP_400_BAD_REQUEST)

像这样的序列化器:

class AccountSerializer(serializers.ModelSerializer):
    password = serializers.CharField(write_only=True,required=False)
    confirm_password = serializers.CharField(write_only=True,required=False)

    class Meta:
        model = Account
        fields = ('id','email','username','created_at','updated_at','first_name','last_name','tagline','password','confirm_password',)
        read_only_fields = ('created_at',)

    def create(self,validated_data):
        return Account.objects.create(**validated_data)

    def update(self,instance,validated_data):
        instance.username = validated_data.get('username',instance.username)

        instance.save()

        password = validated_data.get('password',None)
        confirm_password = validated_data.get('confirm_password',None)

        if password and confirm_password:
            instance.set_password(password)
            instance.save()

            update_session_auth_hash(self.context.get('request'),instance)

        return instance

def validate(self,data):
        if data['password'] and data['confirm_password'] and data['password'] == data['confirm_password']:
            try:
                validate_password(data['password'],user=data['username']):

                return data
            except ValidationError:
                raise serializers.ValidationError("Password is not valid.")
        raise serializers.ValidationError("Passwords do not match.")

在视图的create方法中,它检查序列化程序是否有效,然后保存并根据结果返回响应.我的第一个问题是什么时候调用序列化器create()方法?对我来说,似乎通过在视图的create()方法中调用create_user(模型方法)来完全绕过该方法.它会被调用吗?拥有它有什么意义?

其次,我无法从更新方法返回状态代码,实例保存在序列化程序中.如果验证失败,串行器update()中的代码是否可以工作?

这是我到目前为止:

def update(self,request,pk=None):
        serializer = self.serializer_class(data=request.data)

        if serializer.is_valid():
            << what goes here??? >>

            return Response(serializer.validated_data,status=status.HTTP_200_OK)
        except serializers.ValidationError as e:
        return Response({
            'status': 'Bad request','message': str(e)    
        },status=status.HTTP_400_BAD_REQUEST)

        return Response({
            'status': 'Bad request','message': 'Account could not be updated with received data.'
        },status=status.HTTP_400_BAD_REQUEST)

我迫切需要一些澄清.我不确定如何通过视图/序列化方法请求流程,我不知道如何在序列化程序中保存实例并决定在视图中同时返回哪个响应.

编辑:

我删除了创建和更新方法并修复了AccountViewSet的get_permissions,并添加了用户名验证以按照您的建议进行验证.我还更新了序列化器的创建和更新方法,以下是新版本:

def create(self,validated_data):
    instance = super(AccountSerializer,self).create(validated_data)
    instance.set_password(validated_data['password'])
    instance.save()
    return instance

def update(self,validated_data):
    instance.username = validated_data.get('username',instance.username)

    password = validated_data.get('password',None)
    confirm_password = validated_data.get('confirm_password',None)

    if password and confirm_password:
        instance.set_password(password)
        instance.save()
        update_session_auth_hash(self.context.get('request'),instance)
    else:
        instance.save()

    return instance

我唯一的问题是有必要在创建后调用set_password吗?不创建为新用户设置密码?是否可以在视图中创建和更新代码? serializer.save()在没有视图代码的情况下被调用的位置以及序列化程序验证何时运行而不调用serializer.is_valid()?

解决方法

AccountViewSet:

从你的例子中你不需要.create()和.update()方法 – 现有的方法就足够了

get_permissions() – 首先“if”打开你的系统太宽了imho应该删除 – 你允许任何人做POST – “aka”创建新帐户,这没关系,但其他一切(如GET或PUT) – 应该被允许仅适用于帐户所有者或(如果有需要!)注册用户

AccountSerializer:

> API将在失败的验证时返回HTTP400
>确保id字段是只读的,您不希望有人覆盖现有用户
>现有的create()方法可以删除,但我认为你的应该是这样的:

def create(self,self).create(validated_data)
    instance.set_password(validated_data['password'])
    instance.save()
    return instance

>现有的update()方法……不确定你想要什么,但是:

>第一行允许用户更改其用户名,而无需验证,例如username是唯一的,甚至更多,你根本不检查从请求传递的用户名字段中的内容,它甚至可能是空字符串或无 – 只有在字典中缺少键时才会调用dictionary.get上的回退,
>如果用户名的唯一性将在数据库级别上验证(模型的字段定义中的unique = True) – 您将获得奇怪的异常,而不是API的错误消息)
>接下来是验证密码(再次) – 刚刚在验证方法中测试过
>设置用户密码后,你保存实例..第二次 – 也许值得优化它,只有一个保存?
>如果您不允许更新所有字段,可能最好将update_fields传递给save()以限制更新哪些字段?

>验证 – 只需添加用户名验证;)

只是为了快速理解DRF(非常简化) – 序列化器是API的表单,ViewSets – 通用视图,渲染器是模板(决定数据的显示方式)

– 编辑 –

关于视图集的更多项目,ModelViewSet包括:

> mixins.CreateModelMixin – 调用validate&创建 – > serializer.save – > serializer.create> mixins.RetrieveModelMixin – “get”实例> mixins.UpdateModelMixin – 调用validate&更新/部分更新 – > serializer.save – > serializer.update> mixins.DestroyModelMixin – 调用实例删除> mixins.ListModelMixin – “获取”实例列表(浏览)

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读