Elimina los campos nulos de la respuesta de Django Rest Framework

He desarrollado una API usando django-rest-framework. Estoy utilizando ModelSerializer para devolver datos de un modelo.

modelos.py

class MetaTags(models.Model): title = models.CharField(_('Title'), max_length=255, blank=True, null=True) name = models.CharField(_('Name'), max_length=255, blank=True, null=True) 

serializador.py

 class MetaTagsSerializer(serializers.ModelSerializer): class Meta: model = MetaTags 

respuesta

 { "meta": { "title": null, "name": "XYZ" } } 

Idealmente, en una respuesta API, cualquier valor que no esté presente no debe enviarse en la respuesta. Cuando el title es null , quiero que la respuesta sea:

 { "meta": { "name": "XYZ" } } 

Puedes intentar anular la función to_native:

 class MetaTagsSerializer(serializers.ModelSerializer): class Meta: model = MetaTags def to_native(self, obj): """ Serialize objects -> primitives. """ ret = self._dict_class() ret.fields = self._dict_class() for field_name, field in self.fields.items(): if field.read_only and obj is None: continue field.initialize(parent=self, field_name=field_name) key = self.get_field_key(field_name) value = field.field_to_native(obj, field_name) # Continue if value is None so that it does not get serialized. if value is None: continue method = getattr(self, 'transform_%s' % field_name, None) if callable(method): value = method(obj, value) if not getattr(field, 'write_only', False): ret[key] = value ret.fields[key] = self.augment_field(field, field_name, key, value) return ret 

Básicamente copié la función base to_native de serializers.BaseSerializer y agregué una verificación del valor.

ACTUALIZACIÓN: En cuanto a DRF 3.0, to_native() cambió su nombre a to_representation() y su implementación cambió un poco. Aquí está el código para DRF 3.0 que ignora los valores de cadena nulos y vacíos:

 def to_representation(self, instance): """ Object instance -> Dict of primitive datatypes. """ ret = OrderedDict() fields = self._readable_fields for field in fields: try: attribute = field.get_attribute(instance) except SkipField: continue # KEY IS HERE: if attribute in [None, '']: continue # We skip `to_representation` for `None` values so that fields do # not have to explicitly deal with that case. # # For related fields with `use_pk_only_optimization` we need to # resolve the pk value. check_for_none = attribute.pk if isinstance(attribute, PKOnlyObject) else attribute if check_for_none is None: ret[field.field_name] = None else: ret[field.field_name] = field.to_representation(attribute) return ret 

La respuesta de CubeRZ no me funcionó, usando DRF 3.0.5. Creo que el método to_native se ha eliminado y ahora se reemplaza por to_representation, definido en Serializer en lugar de BaseSerializer.

Utilicé la siguiente clase con DRF 3.0.5, que es una copia del método de Serializer con una ligera modificación.

 from collections import OrderedDict from rest_framework import serializers from rest_framework.fields import SkipField class NonNullSerializer(serializers.ModelSerializer): def to_representation(self, instance): """ Object instance -> Dict of primitive datatypes. """ ret = OrderedDict() fields = [field for field in self.fields.values() if not field.write_only] for field in fields: try: attribute = field.get_attribute(instance) except SkipField: continue if attribute is not None: represenation = field.to_representation(attribute) if represenation is None: # Do not seralize empty objects continue if isinstance(represenation, list) and not represenation: # Do not serialize empty lists continue ret[field.field_name] = represenation return ret 

EDITAR código incorporado de los comentarios

Me enfrenté a un problema similar y lo resolví de la siguiente manera:

 class MetaTagsSerializer(serializers.ModelSerializer): class Meta: model = MetaTags def to_representation(self, instance): ret = super(MetaTagsSerializer, self).to_representation(instance) # Here we filter the null values and creates a new dictionary # We use OrderedDict like in original method ret = OrderedDict(list(filter(lambda x: x[1], ret.items()))) return ret 

O si desea filtrar solo campos vacíos, puede reemplazar la función lambda por lo siguiente:

 lambda x: x[1] is not None 

Encontré que esta solución es la más simple.

 from collections import OrderedDict from rest_framework import serializers class NonNullModelSerializer(serializers.ModelSerializer): def to_representation(self, instance): result = super(NonNullModelSerializer, self).to_representation(instance) return OrderedDict([(key, result[key]) for key in result if result[key] is not None])