【问题标题】:How to extract "label" and "help_text" data from Django Rest Framework serializer?如何从 Django Rest Framework 序列化程序中提取“label”和“help_text”数据?
【发布时间】:2020-03-06 20:55:55
【问题描述】:

我在 models.py 中定义了 Item 模型,如下所示。

class Item(models.Model):
    transaction_id = models.CharField(max_length=25, unique=True)
    order = models.ForeignKey(Order, on_delete=models.CASCADE)
    item_type = models.ForeignKey(ItemType, on_delete=models.SET_DEFAULT, default=1)
    title = models.CharField(max_length=200)
    description = models.TextField(null=True, max_length=3000)
    seller_user_id = models.IntegerField(null=True)
    buyer_user_id = models.IntegerField(null=True)
    listing_id = models.IntegerField(null=True)
    creation_tsz = models.DateTimeField()
    price = models.DecimalField(max_digits=9, decimal_places=2)
    shipping_cost = models.DecimalField(max_digits=9, decimal_places=2)
    quantity = models.IntegerField()
    currency_code = models.CharField(null=True, max_length=5)
    product_data = JSONField(null=True)
    personalization = models.TextField(max_length=1000, null=True)

我还用下面的部分定义了我的 ItemSerializer。

class ItemSerializer(serializers.ModelSerializer):
    id = serializers.IntegerField(read_only=True)
    transaction_id = serializers.CharField(read_only=True, max_length=25)
    title = serializers.CharField(max_length=200)
    description = serializers.CharField(allow_null=True, max_length=3000)
    seller_user_id = serializers.IntegerField(allow_null=True, validators=[validate_positive])
    buyer_user_id = serializers.IntegerField(allow_null=True, validators=[validate_positive])
    listing_id = serializers.IntegerField(allow_null=True, validators=[validate_positive])
    creation_tsz = serializers.DateTimeField()
    price = serializers.DecimalField(label='Price', max_digits=9, decimal_places=2, validators=[validate_positive])
    shipping_cost = serializers.DecimalField(max_digits=9, decimal_places=2, validators=[validate_positive])
    quantity = serializers.IntegerField(read_only=True)
    currency_code = serializers.CharField(allow_null=True, max_length=5)
    product_data = serializers.CharField(allow_null=True)
    personalization = serializers.CharField(max_length=1000, allow_null=True)

    def update(self, item:Item, validated_data):
        #Validating whether
        if 'product_data' in validated_data:
            schema_obj = item.item_type.schema
            try:
                print(validated_data)
                jsonschema.validate(
                    json.loads(validated_data['product_data']),
                    schema=schema_obj)
            except Exception as e:
                raise ValidationError({'product_data':[f'Schema for product data is not valid. {str(e)}']})


        for key in validated_data:
            setattr(item, key, validated_data[key])
        item.save()
        return item

    def validate_product_data(self, value):
        """
        Validate whether property is json parsable
        :param value:
        :return:
        """
        try:
            cur_obj = json.loads(value)
            return value
        except Exception as e:
            raise ValidationError("This field should be in format of JSON.")

在这个问题中,我希望前端应用程序(一个 VueJS 应用程序)能够根据序列化程序标签和 ValidationError 消息自动显示错误消息对话框。因此,我决定通过更改 settings.py 来使用自定义异常处理程序,如下所示。

....
REST_FRAMEWORK = {
    ....
    'EXCEPTION_HANDLER': 'OrderManagement.utils.exception_handler',
    ....
}
....

最后异常处理函数如下所示。

def exception_handler(exc, context):
    response = views.exception_handler(exc, context)
    if isinstance(exc, exceptions.ValidationError):
        response.data['validation_meta'] = {key: {'nicename': NICE_NAME_DICT.get(key, key)} for key in exc.detail}
        ser = context['view'].get_serializer_class()()
    if isinstance(exc, (exceptions.NotAuthenticated)) and response:
        response.status_code = status.HTTP_401_UNAUTHORIZED
    if response:
        response.data['errcode']=response.status_code
    return response

我能够将序列化程序放入“ser”变量,但无法获得所有具有“标签”属性的字段。

收集标签和/或 help_text 信息后,我的目标是为我的 VueJS 应用程序生成如下所示的休息响应。

    {
        "price":[
            "Price should be a number"
            ],
        "metadata":{
            "price":{
                "label":"Price",
                "help_text":""
            }
        }
    } 

我试图通过创建相关序列化程序的对象并使用“get_fields()”方法来获取它。我还尝试收集有关类属性的字段特定数据。

如何从“ser”变量(即上下文序列化程序)中提取所有字段的“标签”属性?我猜“help_text”属性会用类似的方法收集。

【问题讨论】:

  • 您对label 属性有什么特别要求?字段的名称(例如transaction_idtitle)?或者是其他东西?添加一些您预期输出的示例将有助于获得答案
  • 例如ItemSerializer中的price字段有一个label属性,其值为“Price”。为了生成带有附加元数据字段的 ValidationError 响应,我应该在 exception_handler 中收集标签信息,这样我就可以生成如下所示的 Json 响应。 '{ "price":[ "Price 应该是一个数字" ], "metadata":{ "price":{ "label":"Price", "help_text":"" } } }'

标签: django rest django-rest-framework serialization


【解决方案1】:

下面的代码运行良好。首先应该从 ItemSerializer 实例化一个对象,并且字段字典包含所有带有标签和 help_text 数据的字段。

def exception_handler(exc, context):
    response = views.exception_handler(exc, context)
    if isinstance(exc, exceptions.ValidationError):
        ser = context['view'].get_serializer_class()
        ser_obj = ser()
        response.data['validation_meta'] = {}
        for key in exc.detail:
            if key in ser_obj.fields:
                response.data['validation_meta'][key] = {'label': ser_obj.fields[key].label, 'help_text': ser_obj.fields[key].help_text}

    if isinstance(exc, (exceptions.NotAuthenticated)) and response:
        response.status_code = status.HTTP_401_UNAUTHORIZED
    if response:
        response.data['errcode']=response.status_code
    return response

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-07-24
    • 1970-01-01
    • 1970-01-01
    • 2014-08-08
    • 2016-12-18
    • 2017-06-04
    • 1970-01-01
    相关资源
    最近更新 更多