Как изменить имя поля в 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

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

iankit
источник
Я согласился, что 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')
виджей
источник