我创建了一组模型,允许用户为 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/