Как изменить имя поля в Django REST Framework


98

Я пытаюсь изменить имя поля модели в сериализаторе DRF, например псевдоним в SQL. Я пробовал разные методы, но не смог.

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

Я также пытался добавить псевдоним в Django Queryset, но не смог изменить.

Обновлено

Это исключение, с которым я столкнулся

AttributeError at / ViewName / объект 'module' не имеет атрибута 'Field'

Как я могу это сделать?


1
Вы используете правильную реализацию serializers.SerializerMethodFieldподхода? Я имею в виду это: serializers.SerializerMethodField('get_location')иdef get_location(self, obj): ...
— erthalion

Можем ли мы увидеть импорт serializers.py?
— joerick

проголосует против вопроса, потому что OP принял частично неправильный и сбивающий с толку ответ вместо лучшего, приведенного ниже ...
— NeuronQ

Ответы:


59

Вы можете использовать serializers.SerializerMethodField:

Вот модель Park, у которой есть поля name и 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

Вот сериализатор для модели парка, ParkSerializer. Это изменяет имя alternate_name на 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

Кроме того, вы можете использовать serializers.CharFieldс sourceатрибутом:

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

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

__Нотация Django для обхода внешнего ключа также работает:

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

Тот же принцип применяется, если вы хотите изменить тип возвращаемого значения в API, так что вы можете сделать serializers.DecimalField(source=...)и другие типы полей.

Однако это будет работать только для полей только для чтения.


Теперь это исключение бросает AttributeError в / ViewName / объект 'module' не имеет атрибута 'SerializerMethodField'
— Шоаиб Иджаз,

1
Как бы эта тренировка могла создавать и редактировать запросы?
— iankit

1
Строка № 13 «Дзен Питона»: «Должен быть один - и желательно только один - очевидный способ сделать это».
— iankit

14
Это не должен быть принятым ответом. Смотрите ниже, у которого почти в 5 раз больше голосов на момент написания этой статьи.
— cderwin

6
Это плохое решение. sourceВместо этого используйте kwarg, как описано ниже.
— Патрик

215

В полях сериализатора и сериализаторах в целом есть очень хорошая функция, называемая «источник», где вы можете указать источник данных из поля модели.

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

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

Где serializers.SomeSerializerField может быть serializers.CharField, как предлагает ваша модель, но также может быть любым другим полем. Также вы можете поместить вместо этого реляционные поля и другие сериализаторы, и это все равно будет работать как шарм. т.е. даже если alternate_name было полем foreignkey для другой модели.

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

Это также работает с запросами создания, удаления и изменения. Он эффективно создает однозначное сопоставление имени поля в сериализаторе и имени поля в моделях.


Я согласился, что sourceэто более общий подход. Но вы можете увидеть несколько попыток использовать его в вопросе, поэтому, если вы хотите ответить таким образом, вы также должны пояснить, почему исходный код не работает, не так ли?
— erthalion

Ваш код будет работать нормально .. до тех пор, пока запрашивается список и извлечение
— iankit

Оба ответа неполные. В случае внешнего ключа этот метод подразумевает, что при создании нового Park вы должны указать весь родительский объект (alternate_name) в качестве dict в вашем запросе POST, что безумие, поскольку родительский объект уже существует. Следует иметь возможность упоминать внешний экземпляр через его идентификатор.
— Стелиос,

В моем случае (внешний ключ) я решил эту проблему с помощью locations = serializers.PrimaryKeyRelatedField(source='alternate_name', queryset=AlternateName.objects.all()). Видимо, RelatedFieldтоже можно использовать.
— Стелиос,

@chefarov source = 'new_name' - это общий аргумент, который вы можете дать полям сериализатора, отношениям и другим связанным сериализаторам и т. д. Не уверен, почему вы говорите, что ответ неполный.
— iankit

15

Это также будет работать для операций записи

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

    class Meta:
        model = Park
        fields = ('id', 'name', 'location')
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.