python - tutorial - partial update django rest framework
Escribir en un conjunto de objetos como un solo diccionario en Django REST Framework (1)
Creé un conjunto de modelos para permitir a los usuarios definir campos personalizados para ciertos objetos dentro de un proyecto de Django. Esto permite a los usuarios almacenar datos que sean pertinentes a su caso de uso específico sin modificar el esquema de la base de datos. Por ejemplo, el proyecto incluye un modelo de Site
incorporado que tiene un nombre, dirección, etc. Un usuario podría crear un campo personalizado para este modelo si también deseara almacenar, por ejemplo, el punto de contacto designado para cada sitio.
Primero, el usuario crea un campo personalizado y lo asigna a los modelos que quiere que tengan ese campo. Esto está representado por un objeto CustomField
. (Aquí se proporciona una versión simplificada del modelo. La fuente completa está disponible aquí para cualquier persona interesada).
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)
Un segundo modelo contiene los datos de campo personalizados para cada objeto:
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)
Por lo tanto, en nuestro ejemplo, creamos un CustomField denominado point_of_contact
para el modelo de sitio y una instancia de CustomFieldValue
para cada sitio que tiene un POC.
Creé un serializador para representar campos personalizados en la API como un único objeto secundario. Por ejemplo, un Sitio puede aparecer como:
{
"id": 42,
"name": "My Site",
"slug": "site-1",
"physical_address": "123 Fake St",
...
"custom_fields": {
"point_of_contact": "Homer Simpson",
"decommissioned": false
}
}
Una versión simplificada del serializador está debajo ( versión completa ):
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
El contexto custom_fields
es proporcionado por una APIView personalizada ( versión completa ):
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()
Esto funciona muy bien para las operaciones de lectura, pero estoy atascado en cómo apoyar la creación y modificación de campos personalizados a través de la API. El quid de la cuestión parece ser que un serializador espera trabajar en un conjunto de campos que comprende un solo objeto, en lugar de un conjunto de objetos.
¿Cómo puedo extender este serializador para admitir el acceso de escritura a múltiples CustomFieldValues como un solo objeto? Cualquier puntero es muy apreciado.
utilizar esta:
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
puedes usar un método de actualización similar.