So ändern Sie den Feldnamen in Django REST Framework

93

Ich versuche, den Modellfeldnamen in DRF Serializer wie einen Alias ​​in SQL zu ändern. Ich habe verschiedene Methoden ausprobiert, kann aber keinen Erfolg haben.

models.py

class Park(models.Model):
    name = models.CharField(max_length=256)
    alternate_name = models.CharField(max_length=256, blank=True)
    objects = models.GeoManager()

    class Meta:
        db_table = u'p_park'

    def __unicode__(self):
        return '%s' % self.name

    def alias_alternate_name(self):
        return self.alternate_name

serializers.py

class ParkSerializer(serializers.ModelSerializer):

    location = serializers.Field(source='alias_alternate_name')
    #location = serializers.SerializerMethodField(source='alias_alternate_name')

    #alternate_name as location


    class Meta:
        model = Park
        fields = ('id', 'name', 'location')

Ich habe auch versucht, einen Alias ​​in Django Queryset hinzuzufügen, kann ihn aber nicht ändern.

Aktualisiert

Dies ist die Ausnahme, mit der ich konfrontiert bin

AttributeError am Objekt / ViewName / 'module' hat kein Attribut 'Field'

Wie kann ich das machen?

Shoaib Ijaz
quelle
1
Verwenden Sie eine korrekte Implementierung des serializers.SerializerMethodFieldAnsatzes? Ich meine das: serializers.SerializerMethodField('get_location')unddef get_location(self, obj): ...
Erthalion
Können wir die Importe von sehen serializers.py?
Joerick
Ich werde die Frage ablehnen, weil OP eine teilweise falsche und verwirrende Antwort anstelle der besseren unten
akzeptiert hat

Antworten:

56

Sie können verwenden serializers.SerializerMethodField:

Hier ist das Modell Park mit den Feldern Name und Alternate_Name.

class Park(models.Model):
    name = models.CharField(max_length=256)
    alternate_name = models.CharField(max_length=256, blank=True)
    objects = models.GeoManager()

    class Meta:
        db_table = u'p_park'

    def __unicode__(self):
        return '%s' % self.name

Hier ist Serializer für Park Model, ParkSerializer. Dadurch wird der Name von alternative_name in location geändert.

class ParkSerializer(serializers.ModelSerializer):
    location = serializers.SerializerMethodField('get_alternate_name')

    class Meta:
        model = Park
        fields = ('other_fields', 'location')

    def get_alternate_name(self, obj):
        return obj.alternate_name

Zusätzlich können Sie serializers.CharFieldmit sourceAttribut verwenden:

class ParkSerializer(serializers.ModelSerializer):
    location = serializers.CharField(source='other_fields')

    class Meta:
        model = Park
        fields = ('other_fields', 'location')

Djangos __Notation zum Durchlaufen von Fremdschlüsseln funktioniert auch:

location = serializers.CharField(source='OtherModel__other_fields')

Das gleiche Prinzip gilt, wenn Sie den Rückgabetyp in der API ändern möchten, damit Sie dies auch für serializers.DecimalField(source=...)andere Feldtypen tun können .

Dies würde jedoch nur für schreibgeschützte Felder funktionieren.

Erthalion
quelle
Jetzt löst diese Ausnahme AttributeError auf / ViewName / 'module' Objekt hat kein Attribut 'SerializerMethodField'
Shoaib Ijaz
1
Wie würde dieses Training mit Erstellen und Bearbeiten von Anfragen?
Iankit
1
Zeile Nr. 13 von 'Zen of Python': "Es sollte einen - und vorzugsweise nur einen - offensichtlichen Weg geben, dies zu tun."
Iankit
13
Dies sollte nicht die akzeptierte Antwort sein. Siehe die unten stehende, die zum Zeitpunkt meines Schreibens fast fünfmal so viele positive Stimmen hat.
Cderwin
5
Dies ist eine schlechte Lösung. Verwenden sourceSie stattdessen das kwarg wie unten beschrieben.
Patrick
211

In Serializer-Feldern und Serializern im Allgemeinen gibt es eine sehr nette Funktion namens "Quelle", mit der Sie die Datenquelle aus dem Modellfeld angeben können.

class ParkSerializer(serializers.ModelSerializer):
    location = serializers.SomeSerializerField(source='alternate_name')

    class Meta:
        model = Park
        fields = ('other_fields', 'location')

Wobei serializers.SomeSerializerField serializers.CharField sein kann, wie Ihr Modell vorschlägt, aber auch durch eines der anderen Felder. Sie können stattdessen auch relationale Felder und andere Serialisierer einfügen, und dies würde immer noch wie ein Zauber funktionieren. dh selbst wenn alternative_name ein Fremdschlüsselfeld für ein anderes Modell war.

class ParkSerializer(serializers.ModelSerializer):
    locations = AlternateNameSerializer(source='alternate_name', many=true)

    class Meta:
        model = Park
        fields = ('other_fields', 'locations')

class AlternateNameSerializer(serializers.ModelSerialzer):
    class Meta:
        model = SomeModel

Dies funktioniert auch beim Erstellen, Löschen und Ändern von Anforderungen. Es erstellt effektiv eine Eins-zu-Eins-Zuordnung von Feldnamen im Serializer und Feldnamen in Modellen.

iankit
quelle
Ich stimmte zu, das sourceist ein allgemeinerer Ansatz. Sie können jedoch nur wenige Versuche sehen, es in der Frage zu verwenden. Wenn Sie also auf diese Weise antworten möchten, sollten Sie auch klarstellen, warum der ursprüngliche Code nicht funktioniert, nicht wahr?
Erthalion
Ihr Code wird gut funktionieren .. solange die Anfrage für Liste und Abruf ist
iankit
Beide Antworten sind unvollständig. Im Falle eines Fremdschlüssels impliziert diese Methode, dass Sie beim Erstellen eines neuen Parks das gesamte übergeordnete Objekt (alternativer_Name) als Diktat in Ihrer POST-Anforderung angeben müssen, was verrückt ist, da das übergeordnete Objekt bereits vorhanden ist. Man sollte in der Lage sein, die fremde Instanz über ihre ID zu erwähnen.
Stelios
In meinem Fall (Fremdschlüssel) habe ich dieses Problem mit gelöst locations = serializers.PrimaryKeyRelatedField(source='alternate_name', queryset=AlternateName.objects.all()). Anscheinend RelatedFieldkann auch verwendet werden.
Stelios
@chefarov source = 'new_name' ist ein allgemeines Argument, das Sie Serializer-Feldern, Relationen und anderen verwandten Serializern usw. geben können. Sie sind sich nicht sicher, warum Sie sagen, dass die Antwort unvollständig ist.
Iankit
14

Dies würde auch für Schreibvorgänge funktionieren

class ParkSerializer(serializers.ModelSerializer):
    location = serializers.CharField(source='alternate_name')

    class Meta:
        model = Park
        fields = ('id', 'name', 'location')
Vijay
quelle