Como alterar o nome do campo no Django REST Framework

93

Estou tentando alterar o nome do campo Model em DRF Serializer como um alias em SQL. Tentei métodos diferentes, mas não consegui.

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

Também tentei adicionar alias no Django Queryset, mas não consigo alterar.

Atualizada

Esta é a exceção que estou enfrentando

AttributeError em / ViewName / objeto 'módulo' não tem atributo 'Campo'

Como posso fazer isso?

Shoaib Ijaz
fonte
1
Você está usando uma implementação correta da serializers.SerializerMethodFieldabordagem? Quero dizer: serializers.SerializerMethodField('get_location')edef get_location(self, obj): ...
erthalion
Podemos ver as importações de serializers.py?
joerick,
irá negar a pergunta porque OP aceitou uma resposta parcialmente errada e confusa em vez das melhores abaixo ...
NeuronQ

Respostas:

56

Você pode usar serializers.SerializerMethodField:

Aqui está o modelo Park, que possui os campos name e 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

Aqui está o Serializer for Park Model, ParkSerializer. Isso muda o nome de alternate_name para local.

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

Além disso, você pode usar serializers.CharFieldcom o sourceatributo:

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

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

A __notação do Django para atravessar a chave estrangeira também funciona:

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

O mesmo princípio se aplica se você deseja alterar o tipo de retorno na API, portanto, você pode fazer serializers.DecimalField(source=...)e outros tipos de campo também.

No entanto, isso funcionaria apenas para campos somente leitura.

erthalion
fonte
Agora, esta exceção está lançando AttributeError em / ViewName / objeto 'módulo' não tem atributo 'SerializerMethodField'
Shoaib Ijaz
1
Como seria esse treino com criar e editar solicitações?
iankit
1
Linha nº 13 do 'Zen do Python': "Deve haver uma - e de preferência apenas uma - maneira óbvia de fazer isso."
iankit
13
Esta não deve ser a resposta aceita. Veja o abaixo, que tem quase 5 vezes mais votos positivos no momento em que escrevo isso.
cderwin de
5
Esta é uma solução ruim. Use o sourcekwarg como descrito abaixo.
Patrick
212

Há um recurso muito bom nos campos do serializador e serializadores em geral, chamado 'source', onde você pode especificar a fonte dos dados do campo do modelo.

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

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

Onde serializers.SomeSerializerField pode ser serializers.CharField como seu modelo sugere, mas também pode por qualquer um dos outros campos. Além disso, você pode colocar campos relacionais e outros serializadores, e isso ainda funcionaria perfeitamente. ou seja, mesmo se alternate_name for um campo de chave estrangeira para outro modelo.

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

Isso funciona com a criação, exclusão e modificação do tipo de solicitações também. Ele cria efetivamente um mapeamento de nome de campo no serializador e nome de campo em modelos.

iankit
fonte
Eu concordei, essa sourceé uma abordagem mais geral. Mas você pode ver poucas tentativas de usá-lo na pergunta, então, se quiser responder dessa forma, você também deve deixar claro por que o código original não está funcionando, não está?
erthalion
Seu código funcionará bem ... contanto que a solicitação seja para listar e recuperar
iankit
Ambas as respostas estão incompletas. No caso da chave estrangeira, este método implica que ao criar um novo Park, você deve fornecer todo o objeto pai (alternate_name) como um dict em sua solicitação POST, o que é insano, pois o objeto pai já existe. Deve-se ser capaz de mencionar a instância estrangeira por meio de seu id.
stelios
No meu caso (chave estrangeira) resolvi este problema com locations = serializers.PrimaryKeyRelatedField(source='alternate_name', queryset=AlternateName.objects.all()). Aparentemente, também RelatedFieldpode ser usado.
stelios
@chefarov source = 'new_name' é um argumento genérico que você pode dar aos campos do serializador, relações e outros serializadores relacionados, etc. Não tenho certeza porque você disse que a resposta está incompleta.
iankit
14

Isso também funcionaria para operações de gravação

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

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