python - 在 Django REST Framework 中将一组对象作为单个字典写入

标签 python django serialization django-rest-framework

我创建了一组模型,允许用户为 Django 项目中的某些对象定义自定义字段。这允许用户在不修改数据库架构的情况下存储与其特定用例相关的数据。例如,该项目包含一个内置的 Site 模型,它具有名称、地址等。如果用户还想存储,例如,命名的,则可以为此模型创建自定义字段每个站点的联系人。

首先,用户创建一个自定义字段并将其分配给他们希望拥有该字段的模型。这由 CustomField 对象表示。 (这里提供了该模型的简化版本。完整的来源是 available here 感兴趣的人。)

class CustomField(models.Model):
    obj_type = models.ManyToManyField(ContentType, related_name='custom_fields', verbose_name='Object(s)')
    type = models.PositiveSmallIntegerField(choices=CUSTOMFIELD_TYPE_CHOICES, default=CF_TYPE_TEXT)
    name = models.CharField(max_length=50, unique=True)
    label = models.CharField(max_length=50, blank=True)

第二个模型保存每个对象的自定义字段数据:

class CustomFieldValue(models.Model):
    field = models.ForeignKey('CustomField', related_name='values')
    obj_type = models.ForeignKey(ContentType, related_name='+', on_delete=models.PROTECT)
    obj_id = models.PositiveIntegerField()
    obj = GenericForeignKey('obj_type', 'obj_id')
    serialized_value = models.CharField(max_length=255)

因此,在我们的示例中,我们将为 Site 模型创建一个名为 point_of_contact 的 CustomField,并为每个具有 POC 的 Site 创建一个 CustomFieldValue 实例。

我创建了一个序列化程序来将 API 中的自定义字段表示为单个子对象。例如,站点可能显示为:

{
    "id": 42,
    "name": "My Site",
    "slug": "site-1",
    "physical_address": "123 Fake St",
    ...
    "custom_fields": {
        "point_of_contact": "Homer Simpson",
        "decommissioned": false
    }
}

序列化程序的简化版本如下 ( full version ):

class CustomFieldSerializer(serializers.Serializer):
    """
    Extends a ModelSerializer to render any CustomFields and their values associated with an object.
    """
    custom_fields = serializers.SerializerMethodField()

    def get_custom_fields(self, obj):

        # Gather all CustomFields applicable to this object
        fields = {cf.name: None for cf in self.context['view'].custom_fields}

        # Attach any defined CustomFieldValues to their respective CustomFields
        for cfv in obj.custom_field_values.all():
            fields[cfv.field.name] = cfv.value

        return fields

custom_fields 上下文由自定义 APIView (full version) 提供:

class CustomFieldModelAPIView(object):
    """
    Include the applicable set of CustomField in the view context.
    """
    def __init__(self):
        super(CustomFieldModelAPIView, self).__init__()
        self.content_type = ContentType.objects.get_for_model(self.queryset.model)
        self.custom_fields = self.content_type.custom_fields.all()

这对于读取操作非常有用,但我一直在研究如何支持通过 API 创建和修改自定义字段。问题的症结似乎是序列化程序期望处理包含单个对象的一组字段,而不是一组对象。

如何扩展此序列化程序以支持将多个 CustomFieldValues 作为单个对象进行写访问?非常感谢任何指点。

最佳答案

使用这个:

class MySerializer(serializers.ModelSerializer):
    custom_fields = serializer.SerializerMethodField(read_only=True)
    custom_fields_write = serializer.DictField(write_only=True)

    class Meta:
        model = Site
        fields = '__all__'

    def create(self, validated_data):
        custom_fields_data = validated_data.pop('custom_fields_write')
        site = super(MySerializer, self).create(validated_data)
        for key, val in custom_fields_data.items():
            cf = CustomField.objects.get(name=key)
            CustomFieldValue.objects.create(field=cf, obj=site, serialized_value=val)
        return site

您可以使用类似的更新方法。

关于python - 在 Django REST Framework 中将一组对象作为单个字典写入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43591848/

相关文章:

django - 如何使用 order by 对 django orm 更新查询进行限制

python - 参数化 django 的迁移以跳过(--fake 以编程方式)

c++ - 为什么 nlohmann/json 在 double 上序列化 "null"而不是 "0"?

python - 如何在 Odoo 10 上创建自动化任务?

Python: Mechanize

django - 向 Django 用户表单添加验证

php - jquery 序列化和 $.post

c# - 序列化为 JSON 时出现 OutOfMemoryException?

python - 在 Python 中对字符串进行切片

Python PIL NameError 全局名称图像未定义