Comment changer le nom de champ dans Django REST Framework

93

J'essaye de changer le nom de champ de modèle dans DRF Serializer comme alias dans SQL. J'ai essayé différentes méthodes mais je n'y parviens pas.

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

J'ai également essayé d'ajouter un alias dans Django Queryset mais je ne peux pas changer.

Actualisé

C'est l'exception à laquelle je suis confronté

AttributeError at / ViewName / l'objet 'module' n'a pas d'attribut 'Field'

Comment puis-je faire ceci?

Shoaib Ijaz
la source
1
Utilisez-vous une mise en œuvre correcte de l' serializers.SerializerMethodFieldapproche? Je veux dire ceci: serializers.SerializerMethodField('get_location')etdef get_location(self, obj): ...
erthalion
Pouvons-nous voir les importations de serializers.py?
joerick
votera à la baisse parce que OP a accepté une réponse partiellement fausse et déroutante au lieu des meilleures ci-dessous ...
NeuronQ

Réponses:

56

Vous pouvez utiliser serializers.SerializerMethodField:

Voici le modèle Park, qui a des champs de nom et de nom alternatif.

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

Voici Serializer pour Park Model, ParkSerializer. Cela change le nom du nom alternatif en location.

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

De plus, vous pouvez utiliser serializers.CharFieldavec l' sourceattribut:

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

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

La __notation de Django pour traverser la clé étrangère fonctionne également:

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

Le même principe s'applique si vous souhaitez modifier le type de retour sur l'API, vous pouvez donc le faire serializers.DecimalField(source=...)ainsi que d'autres types de champs.

Cela ne fonctionnerait cependant que pour les champs en lecture seule.

erthalion
la source
Maintenant, cette exception lance AttributeError à / ViewName / l'objet 'module' n'a pas d'attribut 'SerializerMethodField'
Shoaib Ijaz
1
Comment cet entraînement avec créer et modifier des demandes?
iankit
1
Ligne n ° 13 de 'Zen of Python': "Il devrait y avoir une - et de préférence une seule - façon évidente de le faire."
iankit
13
Cela ne devrait pas être la réponse acceptée. Voir celui ci-dessous, qui a presque 5 fois plus de votes positifs au moment où j'écris ceci.
cderwin
5
C'est une mauvaise solution. Utilisez sourceplutôt le kwarg comme décrit ci-dessous.
Patrick
212

Il existe une fonctionnalité très intéressante dans les champs de sérialiseur et les sérialiseurs en général appelée «source» où vous pouvez spécifier la source des données à partir du champ de modèle.

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

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

Où serializers.SomeSerializerField peut être serializers.CharField comme le suggère votre modèle, mais peut également être utilisé par l'un des autres champs. Vous pouvez également mettre des champs relationnels et d'autres sérialiseurs à la place et cela fonctionnerait toujours comme un charme. c'est-à-dire même si alter_name était un champ de clé étrangère vers un autre modèle.

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

Cela fonctionne également avec les demandes de type création, suppression et modification. Il crée effectivement un mappage un sur un du nom de champ dans le sérialiseur et du nom de champ dans les modèles.

iankit
la source
Je suis d'accord, c'est sourceune approche plus générale. Mais vous pouvez voir quelques tentatives pour l'utiliser dans la question, donc si vous souhaitez répondre de cette façon, vous devez également expliquer pourquoi le code d'origine ne fonctionne pas, n'est-ce pas?
erthalion le
Votre code fonctionnera bien .. tant que la demande concerne la liste et la récupération
iankit
Les deux réponses sont incomplètes. Dans le cas d'une clé étrangère, cette méthode implique que lors de la création d'un nouveau Park, vous devez donner tout l'objet parent (Alternate_name) comme dict dans votre requête POST, ce qui est insensé puisque l'objet parent existe déjà. On devrait pouvoir mentionner l'instance étrangère via son identifiant.
stelios
Dans mon cas (clé étrangère), j'ai résolu ce problème avec locations = serializers.PrimaryKeyRelatedField(source='alternate_name', queryset=AlternateName.objects.all()). Apparemment, RelatedFieldpeut également être utilisé.
stelios
@chefarov source = 'nouveau_nom' est un argument générique que vous pouvez donner aux champs du sérialiseur, aux relations et aux autres sérialiseurs associés, etc. Je ne sais pas pourquoi vous dites que la réponse est incomplète.
iankit
14

Cela fonctionnerait également pour les opérations d'écriture

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

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