Django Rest框架序列化器和视图

时间:2016-05-31 06:06:14

标签: django serialization django-rest-framework

我很困惑如何在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', 'updated_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)

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

编辑:

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

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, instance, 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之后致电createcreate是否为新用户设置了密码?在createupdate的视图中没有代码可以吗?在没有查看代码的情况下调用serializer.save()的位置以及序列化程序validate何时运行而不调用serializer.is_valid()

2 个答案:

答案 0 :(得分:4)

create()类的AccountViewSet方法中,当序列化程序验证通过时,您正在创建Account实例。相反,你应该打电话给serializer.save()

如果您查看save()课程中的BaseSerializer方法,您会看到它调用create()update()方法,具体取决于模型实例是否正在创建或更新。由于您未在serializer.save()方法中调用AccountViewSet.create(),因此未调用AccountSerializer.create()方法。希望这能回答你的第一个问题。

你的第二个问题的答案是缺少serializer.save()。将<< what goes here??? >>替换为serializer.save()。这(如上所述)将调用AccountSerializer.update()方法。

答案 1 :(得分:3)

<强> AccountViewSet

从您的示例中,您不需要.create().update()方法 - 现有方法应该足够了

get_permissions() - 首先&#34;如果&#34;正在打开你的系统太宽了imho应该删除 - 你允许任何人做POST - &#34;又名&#34;创建新帐户,这没关系,但其他所有内容(例如GETPUT) - 只应该允许帐户所有者或(如果有需要!)注册用户

<强> AccountSerializer

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

    def create(self, validated_data):
        instance = super(AccountSerializer, self).create(validated_data)
        instance.set_password(validated_data['password'])
        instance.save()
        return instance
    
  • 现有update()方法......不确定您想要什么,但是:

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

只是为了快速了解DRF(非常简化) - Serializers是API FormsViewSets - 通用Views,渲染器是templates (决定数据的显示方式)

- 编辑 -

有关视图集的更多项目,ModelViewSet包含:

  • mixins.CreateModelMixin - 调用validate&amp;创建 - &gt; serializer.save - &gt; serializer.create
  • mixins.RetrieveModelMixin - &#34; get&#34;实例
  • mixins.UpdateModelMixin - 调用validate&amp;更新/部分更新 - &gt; serializer.save - &gt; serializer.update
  • mixins.DestroyModelMixin - 调用实例删除
  • mixins.ListModelMixin - &#34; get&#34;实例列表(浏览)