2014-11-19 4 views
6

Ho sviluppato un'API utilizzando django-rest-framework. Sto utilizzando ModelSerializer per restituire i dati di un modello.Rimuovi campi null dalla risposta Django Rest Framework

models.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) 

serializer.py

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

risposta

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

Idealmente in un A Risposta PI qualsiasi valore che non è presente non deve essere inviato nella risposta. Quando il title è null voglio la risposta sia:

{ 
    "meta": { 
     "name": "XYZ" 
    } 
} 
+0

_Ideale in una risposta API qualsiasi valore che non è presente non deve essere inviato nella risposta. Cosa ti fa pensare che? –

+0

Ad esempio: Facebook graph api restituisce solo i dati di un profilo consentito da access_token. @VincentBeltman –

+0

Non consentito da access_token è completamente diverso da non esistente. –

risposta

4

Si potrebbe provare l'override la funzione 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 

ho praticamente copiato la funzione to_native base dalla serializers.BaseSerializer e ha aggiunto un assegno per la valore.

+0

Eeeek !!! E 'stato davvero intelligente. Works :) –

15

La risposta di CubeRZ non ha funzionato per me, utilizzando DRF 3.0.5. Penso che il metodo to_native sia stato rimosso e ora viene sostituito da to_representation, definito in Serializer invece di BaseSerializer.

Ho usato la classe qui sotto con DRF 3.0.5, che è una copia del metodo da Serializer con una leggera modifica.

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 

EDIT codice incorporato dai commenti

+0

Ho dovuto aggiungere una verifica aggiuntiva nel caso in cui i campi fossero oggetti stessi: 'se l'attributo non è None: representation = field.to_representation (attributo) se la rappresentazione non è None: ret [field.field_name] = representation' – db0

+1

@ db0 Grazie. Questo mi ha ricordato che vorrei anche saltare le liste vuote. –

10

ho affrontato un problema simile e risolto nel modo seguente:

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 

Oppure, se si desidera filtrare solo i campi vuoti è possibile sostituire il lambda funzione da quanto segue:

lambda x: x[1] is not None 
+0

So che è già da un pezzo, ma entrambi i lambda non producono lo stesso risultato? Quali sono le loro differenze? Potrei mancare qualcosa. –

+0

Per capire la differenza prova questo: '' ' l = ['', 0, Nessuno, [],()] stampa (lista (filtro (lambda x: x, l))) stampa (lista (filtro (lambda x: x non è None, l))) '' ' L'espressione' x non è None' filtra solo None, ma solo 'x' filtra qualsiasi oggetto che converte in bool come' False' – asduj

1

Ho trovato questa soluzione la più semplice.

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])