【问题标题】:Django Rest Framework: Deserializing and get the primary key from validated_dataDjango Rest Framework:反序列化并从validated_data中获取主键
【发布时间】:2015-03-30 15:13:07
【问题描述】:

我定义了一个嵌套模型Product 如下。每个Product可以属于很多Productlist

class Product(models.Model):
    product_id = models.AutoField(primary_key=True)
    product_name = models.CharField(max_length=50)

class Productlist(models.Model):
    productlist_id = models.AutoField(primary_key=True)
    productlist_name = models.CharField(max_length=50)
    product = models.ManyToManyField(Product, related_name='productlists')

对应的序列化器是:

class ProductlistSerializer(serializers.ModelSerializer):
    class Meta:
        model = Productlist
        fields = ('productlist_id', 'productlist_name',)

class ProductSerializer(serializers.ModelSerializer):
    productlists = ProductlistSerializer(many=True, required=False)

    class Meta:
        model = Product
        fields = ('product_id', 'product_name', 'product lists')

    def create(self, validated_data):
        #some codes

当我POST 一个新的Product (url(r'^api/products/$', views.ProductEnum.as_view()) 时,我想更新产品列表,以便将新产品添加到相应的产品列表中。我更喜欢使用的 JSON 文件是:

{
    "product_name": "product1"
    "productlist": [
        {
            "productlist_id": 1,
            "productlist_name": "list1",
        },
        {
            "productlist_id": 2,
            "productlist_name": list2"
        }
    ]
}

问题是我无法从validated_data 获得productlist_id。在 Django Rest Framework 中,总是需要调用to_internal_value() 来反序列化数据并生成validated_data。经过一番调试,我检查了DRF的代码,在to_internal_value()中找到了以下sn-ps:

def to_internal_value(self, data):
    """
    Dict of native values <- Dict of primitive datatypes.
    """
    if not isinstance(data, dict):
        message = self.error_messages['invalid'].format(
            datatype=type(data).__name__
        )
        raise ValidationError({
            api_settings.NON_FIELD_ERRORS_KEY: [message]
        })

    ret = OrderedDict()
    errors = OrderedDict()
    fields = [
        field for field in self.fields.values()
        if (not field.read_only) or (field.default is not empty)
    ]

    for field in fields:
        validate_method = getattr(self, 'validate_' + field.field_name, None)
        primitive_value = field.get_value(data)
        try:
            validated_value = field.run_validation(primitive_value)
            if validate_method is not None:
                validated_value = validate_method(validated_value)
        except ValidationError as exc:
            errors[field.field_name] = exc.detail
        except DjangoValidationError as exc:
            errors[field.field_name] = list(exc.messages)
        except SkipField:
            pass
        else:
            set_value(ret, field.source_attrs, validated_value)

    if errors:
        raise ValidationError(errors)

    return ret

请注意to_internal_value的字段忽略了IntegerField(read_only=True),因为它不能满足以下条件:

        fields = [
            field for field in self.fields.values()
            if (not field.read_only) or (field.default is not empty)
        ]

所以validated_data 将只有以下数据:

{
    "product_name": "product1"
    "productlist": [
        {
            "productlist_name": "list1",
        },
        {
            "productlist_name": list2"
        }
    ]
}

如何获取产品列表的主键?提前致谢!

【问题讨论】:

    标签: json django primary-key django-rest-framework nested-lists


    【解决方案1】:

    经过一番挖掘,我发现read_only 字段仅用于输出呈现。你可以在Django REST Framework的官方githublink找到类似的问题。

    因此解决方案是覆盖序列化程序中的read_only 字段,如下所示:

    class ProductlistSerializer(serializers.ModelSerializer):
        productlist_id = serializers.IntegerField(read_only=False)
    
        class Meta:
            model = Productlist
            fields = ('productlist_id', 'productlist_name',)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-08-08
      • 2017-10-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-07-28
      • 1970-01-01
      相关资源
      最近更新 更多