django rest framework学习使用总结

Ⅰ.走drf序列化创建、更新注意事项
①当某一字段不是必传的时候,前端传了该字段,值是""空字符串,这个时候创建就会报错,没有办法进行创建,提示这个字段必须要传值
解决方法:
对该字段的序列加入 allow_blank=True

class ApplySerializer(serializers.ModelSerializer):
    last_version = serializers.CharField(required=False, allow_blank=True)
    approve_second = serializers.CharField(required=False, allow_blank=True)
    task_name = serializers.CharField(required=False, allow_blank=True)

②序列化校验规则
1.单个字段的校验

class AvailAreaSerializer(serializers.ModelSerializer):
    name = serializers.CharField(
        validators=[UniqueValidator(
            queryset=AvailArea.objects.filter(is_delete=False), message=u'name已存在')]
    )

2.多个字段的校验

class CodeConfigSerializer(serializers.ModelSerializer):
    bk_id = serializers.IntegerField(required=True)

    class Meta:
        model = CodeConfig
        fields = '__all__'
        validators = [
            UniqueTogetherValidator(
                queryset=CodeConfig.objects.all(),
                fields=(
                    'bk_type', 'bk_code',
                ),
                message='该类型编码已被使用'
            )
        ]

3.自定义验证器

key_validator = RegexValidator(
    re.compile('^[_a-zA-Z0-9]+$'),
    message=_(u'请输入合法编码:英文数字及下划线'),
    code='invalid',
)

class DictDataSerializer(serializers.ModelSerializer):
    """数据字典数据项序列化"""

    key = serializers.CharField(required=True, error_messages={'blank': _(u"编码不能为空")}, max_length=LEN_LONG,
                                validators=[key_validator])

权重顺序:自定义验证器 > 单个字段的验证 > 多个字段的验证
注意事项:执行序列表创建、更新都会进行校验的
若想创建时进行校验,更新时不校验,个人建议的方法进行create方法的重写

class ProStoreConfigSerializer(serializers.ModelSerializer):

    class Meta:
        model = ProStoreConfig
        exclude = ('is_deleted',)

    def create(self, validated_data):
        if not result:
            raise serializers.ValidationError("制品库配置账户密码错误")
        queryset = ProStoreConfig.objects.all()
        if queryset.count():
            raise serializers.ValidationError("制品库配置已配置过了")
        else:
            instance = super(ProStoreConfigSerializer, self).create(validated_data=validated_data)
        return instance

Ⅱ.列表的过滤
1.原字段过滤

class BasicConfigFilter(django_filters.FilterSet):
    bk_biz_id = django_filters.Filter(name='bk_biz_id')
    bk_cluster_id = django_filters.Filter(name='bk_cluster_id')
    bk_module_id = django_filters.Filter(name='bk_module_id')

    class Meta:
        model = BasicConfig
        fields = '__all__'

2.前端单字段对应后端多个字段搜索
前端一个输入框,根据接收人、手机号搜索,像后端传入receiver

class NotifyLogFilter(django_filters.FilterSet):
    receiver = django_filters.Filter(method="filter_receiver", help_text="接收者匹配")

    class Meta:
        model = NotifyLog
        fields = '__all__'

    def filter_receiver(self, queryset, name, value):
        return queryset.filter(Q(receiver_name__icontains=value) | Q(receiver_phone__icontains=value))

3.自定义字段过滤

class ApplyFilter(django_filters.FilterSet):
    bk_biz_id = django_filters.Filter(name='bk_biz_id', method="filter_by_bk_biz_id")
    bk_cluster_id = django_filters.Filter(name='bk_cluster_id', method="filter_by_bk_cluster_id")
    bk_module_id = django_filters.Filter(name='bk_module_id', method="filter_by_bk_module_id")
    now_version = django_filters.Filter(name="now_version", lookup_expr="icontains")
    creator = django_filters.Filter(name="creator", method="filter_by_creator")

    class Meta:
        model = Apply
        fields = '__all__'

    def filter_by_creator(self, queryset, name, value):
        if value == "admin":
            return queryset
        else:
            return queryset.filter(creator=value)

    def filter_by_bk_biz_id(self, queryset, name, value):
        return queryset.filter(basic_config__bk_biz_id=value)

    def filter_by_bk_cluster_id(self, queryset, name, value):
        return queryset.filter(basic_config__bk_cluster_id=value)

    def filter_by_bk_module_id(self, queryset, name, value):
        return queryset.filter(basic_config__bk_module_id=value)

弊端:当某些过滤字段,是根据request进行获取的,是没有办法进行过滤的。其次搜索的内容,你想根据前端的某些字段值变更搜索结果中的字段值,是无法进行变更的,不支持设置属性值,只有重写list方法
Ⅲ.增加序列化返回的自定义字段

class BasicConfig(Model):
    bk_biz_id = models.IntegerField(_('业务id'), null=True)
    bk_cluster_id = models.IntegerField(_('集群id'), null=True)
    bk_module_id = models.IntegerField(_('模块id'), null=True)
    publish_count = models.IntegerField(_('版本发布次数'), default=1)
    # 0 未启用 1 已启用
    status = models.BooleanField(_('启用状态'), default=0)

    class Meta:
        app_label = "configs"
        verbose_name = _("基础配置")
        verbose_name_plural = _("基础配置")

    @property
    def bk_biz_name(self):
        bk_biz_name, _, _ = self.get_topo_data
        return bk_biz_name

    @property
    def bk_cluster_name(self):

        _, bk_cluster_name, _ = self.get_topo_data
        return bk_cluster_name

    @property
    def bk_module_name(self):
        _, _, bk_module_name = self.get_topo_data
        return bk_module_name

    @property
    def get_topo_data(self):
        result = cache.get(CACHE_BIZ_TOPOLOGY_NAME)
        if not result:
            result = get_biz_topology()
        data = result.get(self.bk_biz_id)
        bk_biz_name = data.get('bk_inst_name')
        bk_cluster_name = None
        bk_module_name = None
        for i in data.get('child'):
            if i.get('bk_inst_id') == self.bk_cluster_id:
                bk_cluster_name = i.get('bk_inst_name')
            for j in i.get('child'):
                if j.get('bk_inst_id') == self.bk_module_id:
                    bk_module_name = j.get('bk_inst_name')
        return bk_biz_name, bk_cluster_name, bk_module_name

    @property
    def process_config(self):
        process_config_obj = ProcessConfig.objects.get(basic_config=self)
        return model_to_dict(process_config_obj)

    @property
    def version_config(self):
        version_config_obj = VersionConfig.objects.get(basic_config=self)
        return model_to_dict(version_config_obj)

    @property
    def approve_config(self):
        approve_config_obj = ApproveConfig.objects.get(basic_config=self)
        return model_to_dict(approve_config_obj)

    @property
    def bk_biz_code(self):
        biz_obj = CodeConfig.objects.filter(bk_id=self.bk_biz_id, bk_type=BIZ)
        return biz_obj[0].bk_code if biz_obj else None

    @property
    def bk_cluster_code(self):
        cluster_obj = CodeConfig.objects.filter(bk_id=self.bk_cluster_id, bk_type=CLUSTER)
        return cluster_obj[0].bk_code if cluster_obj else None

    @property
    def bk_module_code(self):
        module_obj = CodeConfig.objects.filter(bk_id=self.bk_module_id, bk_type=MODULE)
        return module_obj[0].bk_code if module_obj else None

    def code_version(self, date_time):
        code_version = \
            str(self.bk_biz_code) \
            + date_time + str(self.bk_module_code) + "." + str(self.publish_count)
        return code_version

序列化返回自定义字段,不需要重新to_representation(self, instance)方法

class BasicConfigSerializer(serializers.ModelSerializer):
    bk_biz_id = serializers.IntegerField(required=True)
    bk_cluster_id = serializers.IntegerField(required=True)
    bk_module_id = serializers.IntegerField(required=True)

    class Meta:
        model = BasicConfig
        fields = ('id', 'bk_biz_id', 'bk_cluster_id', 'bk_module_id',
                  'bk_biz_name', 'bk_cluster_name', 'bk_module_name',
                  'bk_biz_code', 'bk_cluster_code', 'bk_module_code',
                  'process_config', 'version_config', 'approve_config',
                  'status', 'publish_count',
                  'updated_by', 'update_at',
                  'creator', 'create_at'
                  )
        validators = [
            UniqueTogetherValidator(
                queryset=BasicConfig.objects.filter(is_deleted=0),
                fields=(
                    'bk_biz_id', 'bk_cluster_id', 'bk_module_id'
                ),
                message='该系统环境已配置过发布流程'
            )
        ]

Ⅳ.自定义方法接受参数注意

class ProcessConfigViewSet(component_viewsets.ModelViewSet):
    serializer_class = ProcessConfigSerializer
    queryset = ProcessConfig.objects.all()

    @list_route(methods=['POST'], url_path='get_topology_data')
    def get_topology_data(self, request):
        """从缓存中获取业务拓扑"""
        # params = {'bk_biz_id': 2}
        params = request.data
        result = cache.get(CACHE_BIZ_TOPOLOGY_NAME)
        if not result:
            result = get_biz_topology()
        result = result.get(params.get('bk_biz_id')).get('child')
        return Response({"items": result, "count": len(result)})

注意:当自定义方法是POST请求时,用request.data进行接受,不要采用request.body接受,在本地开发时,request.body可以接受到前端的传值,当部署到线上的时候,request.body是无法取到前端的传值,用request.data。
并且request.data取值,直接就是json,不需要再json.loads()。

猜你喜欢

转载自blog.csdn.net/qq_42631707/article/details/106915583