Ich habe zwei Modelle, eines mit M2M-Beziehung und einem verwandten Namen. Ich möchte alle Felder in den Serializer und das zugehörige Feld aufnehmen.
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__'
Dies funktioniert, schließt jedoch das zugehörige Feld nicht ein.
fields = ['name', 'price', 'pizzas']
Das funktioniert genau so, wie ich es möchte, aber was passiert, wenn das Toppings-Modell viele Felder hat? Ich möchte etwas machen wie:
fields = ['__all__', 'pizzas']
Diese Syntax führt zu einem Fehler, der besagt:
Feldname
__all__
gilt nicht für das Modell
Gibt es eine Möglichkeit, das gewünschte Verhalten zu erreichen? Oder müssen die Felder manuell eingegeben werden, wenn ein verwandter Name verwendet wird?
Ich habe gerade den Quellcode von Django Rest Framework überprüft. Das gewünschte Verhalten scheint im Framework nicht unterstützt zu werden.
Die Option fields
muss eine Liste, ein Tupel oder der Text __all__
Sein.
Hier ist ein Ausschnitt des relevanten Quellcodes:
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__
)
Sie können 'all' nicht zusätzlich zum Tupel oder zur Liste mit Feldern hinzufügen ...
Wie @DanEEStart sagte, haben DjangoRestFramework keine einfache Möglichkeit, den Wert ' all ' für Felder zu erweitern, da die Methoden get_field_names
scheint entworfen zu sein m so zu arbeiten .
Glücklicherweise können Sie diese Methode außer Kraft setzen, um auf einfache Weise alle Felder und Beziehungen einzuschließen, ohne Tonnen von Feldern aufzuzählen.
Ich überschreibe diese Methode wie folgt:
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
Beachten Sie, dass diese Methode nur das Verhalten dieses Serialisierers ändert und das Attribut extra_fields
Nur für diese Serialisiererklasse funktioniert.
Wenn Sie über eine Menge solcher Serializer verfügen, können Sie eine Zwischenklasse erstellen, die diese get_fields_names
- Methode an einem Ort einschließt und sie mehrmals wiederverwendet. Etwas wie das:
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']
Ein altes Problem, dachte aber, dass dies anderen in Zukunft helfen könnte.
Ich habe gerade ein ähnliches Problem festgestellt und festgestellt, dass die Option " all " funktioniert, indem ein zusätzliches Feld manuell wie im folgenden Beispiel angegeben wird. Ich bin mir nicht sicher, ob dies auch Ihr Problem lösen würde. Es ist ein verdammt sauberer Anblick als alles andere, was ich gesehen habe.
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__'
Ich gehe davon aus, dass dies für alle anderen verwandten Feldoptionen funktioniert, die auf derselben Seite aufgeführt sind: http://www.Django-rest-framework.org/api-guide/relations/#serializer-relations =
Ich verwende das Django Rest Framework Version 3.6.2
Reverse Relations Beispiel wie gewünscht:
class TrackSerializer(serializers.ModelSerializer):
album = AlbumSerializer(source='album_id')
class Meta:
model = Track
fields = '__all__'
Hallo, ich könnte das erwartete Ergebnis erzielen, indem ich Djangos _meta API verwende, das anscheinend verfügbar ist seit Django 1.11. Also habe ich in meinem Serializer Folgendes getan:
model = MyModel
fields = [field.name for field in model._meta.fields]
fields.append('any_other_field')
In der Programmierung gibt es immer viele Möglichkeiten, das gleiche Ergebnis zu erzielen, aber diese oben hat wirklich für mich funktioniert.
Prost!
um alle Felder und die anderen in Ihrem Serializer definierten Felder einzuschließen, können Sie einfach exclude = ()
sagen.
class ToppingSerializer(serializers.HyperlinkedModelSerializer):
pizzas = '<>' #the extra attribute value
class Meta:
model = Topping
exclude = ()
Dies listet alle Feldwerte mit dem zusätzlichen Argument pizzas auf
So habe ich es gemacht, viel einfacher
class OperativeForm(forms.ModelForm):
class Meta:
model = Operative
fields = '__all__'
exclude = ('name','objective',)
widgets = {'__all__':'required'}