2016-07-07 47 views
7

Ho due modelli, uno con relazione M2M e un nome correlato. Voglio includere tutti i campi nel serializzatore e il campo correlato.Framework Django Rest, come includere i campi "__all__" e un campo correlato in ModelSerializer?

models.py:

class Pizza(models.Model): 
    name = models.CharField(max_length=50, unique=True) 
    toppings = models.ManyToManyField(Topping, null=True, blank=True, related_name='pizzas') 

class Topping(models.Model): 
    name = models.CharField(max_length=50, unique=True) 
    price = models.IntegerField(default=0) 

serializer.py:

class ToppingSerializer(serializers.ModelSerializer): 
    class Meta: 
     model = Topping 
     fields = '__all__' 

Questo funziona, ma non include il campo relativo.

fields = ['name', 'price', 'pizzas'] 

Questo funziona esattamente come voglio, ma cosa succede quando il modello Topping ha un sacco di campi. Voglio fare qualcosa di simile:

fields = ['__all__', 'pizzas'] 

risultati Questa sintassi in un errore che dice:

Nome campo __all__ non è valida per il modello

C'è un modo per ottenere il desiderato comportamento? O i campi devono essere digitati manualmente quando si utilizza un nome correlato?

+0

http://stackoverflow.com/ domande/14573102/how-do-i-include-related-model-fields-using-django-rest-framework - La risposta non può essere migliorata, se è dell'autore stesso. – karthikr

+0

@karthikr Questo in realtà non spiega come fare ciò che voglio. Spiega semplicemente come annidare M2M. Non voglio farlo. Voglio includere campi correlati e il tag __all__ nei "campi" del serializzatore – Curtwagner1984

risposta

6

Ho appena controllato il codice sorgente di Django Rest Framework. Il comportamento che si desidera sembra non essere supportato nel Framework.

L'opzione fields deve essere una lista, una tupla o il testo __all__.

Ecco un frammento del codice sorgente relativo:

ALL_FIELDS = '__all__' 
    if fields and fields != ALL_FIELDS and not isinstance(fields, (list, tuple)): 
     raise TypeError(
      'The `fields` option must be a list or tuple or "__all__". ' 
      'Got %s.' % type(fields).__name__ 
     ) 

Non è possibile aggiungere 'tutto' in aggiunta al tupla o una lista con i campi ...

13

Come @DanEEStart detto, DjangoRestFramework non è un modo semplice per estendere il valore 'all' per i campi, perché i metodi get_field_names sembrano essere progettati to work that way.

Ma fortunatamente è possibile sovrascrivere questo metodo per consentire un modo semplice per includere tutti i campi e le relazioni senza enumerare una tonnellata di campi.

sovrascrivo questo metodo come questo:

class ToppingSerializer(serializers.ModelSerializer): 

    class Meta: 
     model = Topping 
     fields = '__all__' 
     extra_fields = ['pizzas'] 

    def get_field_names(self, declared_fields, info): 
     expanded_fields = super(ToppingSerializer, self).get_field_names(declared_fields, info) 

     if getattr(self.Meta, 'extra_fields', None): 
      return expanded_fields + self.Meta.extra_fields 
     else: 
      return expanded_fields 

Nota che questo metodo solo cambiare il comportamento di questo serializzatore, e l'attributo extra_fields funziona solo su questa classe serializer.

Se si dispone di un numero di serializzatore come questo, è possibile creare una classe intermedia per includere questo metodo get_fields_names in un unico punto e riutilizzarlo molte volte. Alcuni come questo:

class CustomSerializer(serializers.HyperlinkedModelSerializer): 

    def get_field_names(self, declared_fields, info): 
     expanded_fields = super(CustomSerializer, self).get_field_names(declared_fields, info) 

     if getattr(self.Meta, 'extra_fields', None): 
      return expanded_fields + self.Meta.extra_fields 
     else: 
      return expanded_fields 


class ToppingSerializer(CustomSerializer): 

    class Meta: 
     model = Topping 
     fields = '__all__' 
     extra_fields = ['pizzas'] 

class AnotherSerializer(CustomSerializer): 

    class Meta: 
     model = Post 
     fields = '__all__' 
     extra_fields = ['comments'] 
+0

Voglio solo farti sapere che sei un vero toccasana e ti ringrazio tanto per questo frammento. – Hondros

1

Un vecchio problema, ma pensato che questo potrebbe aiutare gli altri in futuro.

Ho appena ricevuto un problema simile e ho ottenuto l'opzione "all" specificando un campo aggiuntivo manualmente come nell'esempio seguente. Non sono sicuro che questo risolva anche il tuo problema. È dannatamente più pulito di qualsiasi altra cosa che ho visto.

http://www.django-rest-framework.org/api-guide/relations/#nested-relationships

class TrackSerializer(serializers.ModelSerializer): 
    class Meta: 
     model = Track 
     fields = '__all__' 

class AlbumSerializer(serializers.ModelSerializer): 
    tracks = TrackSerializer(many=True, read_only=True) 

    class Meta: 
     model = Album 
     fields = '__all__' 

vorrei assumere questo dovrebbe funzionare per una qualsiasi delle altre opzioni di campo relativi elencati nella stessa pagina: http://www.django-rest-framework.org/api-guide/relations/#serializer-relations

sto usando la versione di Django Resto Framework 3.6.2

esempio relazione inversa come richiesto:

class TrackSerializer(serializers.ModelSerializer): 
    album = AlbumSerializer(source='album_id') 

    class Meta: 
     model = Track 
     fields = '__all__' 
+0

questo non funzionerebbe in caso di relazioni inverse -> http://www.django-rest-framework.org/api-guide/relations/#reverse-relations –

+0

@IshanKhare Aggiornato per mostrare che questo può funzionare anche con relazioni inverse . –

+0

Questa dovrebbe essere accettata come risposta corretta, in quanto risolve il problema all'interno della funzionalità fornita dal framework senza ulteriore hacking. – MrName

1

per includere tutti i campi e gli altri campi definiti nel serializzatore si può solo dire exclude =()

class ToppingSerializer(serializers.HyperlinkedModelSerializer): 
    pizzas = '<>' #the extra attribute value 
    class Meta: 
     model = Topping 
     exclude =() 

Questo elenco di tutti i valori del campo con le pizze argomento extra

Problemi correlati