Как извлечь данные «label» и «help_text» из сериализатора Django Rest Framework? - PullRequest
0 голосов
/ 06 марта 2020

Я определил модель Item в models.py точно так же, как показано ниже.

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", но я не смог получить все поля со свойствами "label".

После сбора информации метки и / или help_text моя цель состоит в том, чтобы получить ответ покоя, как показано ниже для моего VueJS приложения.

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

Я попытался получить его, создав объект, связанный с сериализатор и использовать метод "get_fields ()". Я также пытался собрать данные о полях c данных о свойствах класса.

Как я могу извлечь свойства "label" всех полей из переменной 'ser' (которая является контекстным сериализатором)? Я предполагаю, что свойство "help_text" будет собираться по аналогичной методике.

1 Ответ

1 голос
/ 07 марта 2020

Код ниже работал так хорошо. Во-первых, должен быть создан экземпляр объекта из ItemSerializer, а в словаре полей есть все поля с данными label и 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
...