J'ai deux modèles, un avec une relation M2M et un nom apparenté. Je veux inclure tous les champs dans le sérialiseur et le champ associé.
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__'
Cela fonctionne mais il n'inclut pas le champ associé.
fields = ['name', 'price', 'pizzas']
Cela fonctionne exactement comme je le souhaite, mais que se passe-t-il lorsque le modèle Toppings comporte de nombreux champs. Je veux faire quelque chose comme:
fields = ['__all__', 'pizzas']
Cette syntaxe entraîne une erreur disant:
Nom de domaine
__all__
n'est pas valide pour le modèle
Existe-t-il un moyen d'atteindre le comportement souhaité? Ou les champs doivent être saisis manuellement lors de l'utilisation d'un nom associé?
Je viens de vérifier le code source de Django Rest Framework. Le comportement que vous souhaitez ne semble pas être pris en charge dans le Framework.
L'option fields
doit être une liste, un Tuple ou le texte __all__
.
Voici un extrait du code source pertinent:
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__
)
Vous ne pouvez pas ajouter 'all' en plus du Tuple ou de la liste avec des champs ...
Comme l'a dit @DanEEStart, DjangoRestFramework n'a pas de moyen simple d'étendre la valeur ' all ' pour les champs, car le get_field_names
les méthodes semblent être conçues pour fonctionner de cette façon .
Mais heureusement, vous pouvez remplacer cette méthode pour permettre un moyen simple d'inclure tous les champs et les relations sans énumérer une tonne de champs.
Je remplace cette méthode comme ceci:
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
Notez que cette méthode modifie uniquement le comportement de ce sérialiseur et que le extra_fields
l'attribut ne fonctionne que sur cette classe de sérialiseur.
Si vous avez des tonnes de sérialiseur comme celui-ci, vous pouvez créer une classe intermédiaire pour inclure ce get_fields_names
méthode en un seul endroit et réutilisation plusieurs fois. Certains aiment ça:
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']
Un vieux problème mais pensait que cela pourrait aider d'autres à l'avenir.
Je viens de rencontrer un problème similaire et j'ai obtenu l'option " all " en spécifiant manuellement un champ supplémentaire selon l'exemple suivant. Je ne sais pas si cela résoudrait également votre problème. C'est une foutue vue plus propre que tout ce que j'ai vu.
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__'
Je suppose que cela fonctionnerait pour toutes les autres options de champ connexes répertoriées sur la même page: http://www.Django-rest-framework.org/api-guide/relations/#serializer-relations =
J'utilise le Django Rest Framework version 3.6.2
Exemple de relation inverse comme demandé:
class TrackSerializer(serializers.ModelSerializer):
album = AlbumSerializer(source='album_id')
class Meta:
model = Track
fields = '__all__'
Salut, je pourrais atteindre le résultat attendu en utilisant API _meta de Django , qui semble être disponible depuis Django 1.11. Donc, dans mon sérialiseur, j'ai fait:
model = MyModel
fields = [field.name for field in model._meta.fields]
fields.append('any_other_field')
En programmation, il y a toujours plusieurs façons d'obtenir le même résultat, mais celui ci-dessus, a vraiment fonctionné pour moi.
À votre santé!
pour inclure tous les champs et les autres champs définis dans votre sérialiseur, vous pouvez simplement dire exclude = ()
class ToppingSerializer(serializers.HyperlinkedModelSerializer):
pizzas = '<>' #the extra attribute value
class Meta:
model = Topping
exclude = ()
Ceci listera toutes les valeurs de champ avec l'argument supplémentaire pizzas
Voilà comment je l'ai fait, beaucoup plus facile
class OperativeForm(forms.ModelForm):
class Meta:
model = Operative
fields = '__all__'
exclude = ('name','objective',)
widgets = {'__all__':'required'}