Як змінити назву поля в Django REST Framework


98

Я намагаюся змінити ім'я поля моделі в DRF Serializer, як псевдонім у 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, але не можу змінити.

Оновлено

Це виняток, з яким я стикаюся

Помилка AttributeEr на об'єкті / ViewName / 'module' не має атрибута 'Field'

Як я можу це зробити?


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

Чи можемо ми побачити імпорт serializers.py?
— joerick

проголосує за питання, оскільки ОП прийняв частково неправильну та заплутану відповідь замість кращих нижче ...
— NeuronQ

Відповіді:


58

Ви можете використовувати 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

Ось Serializer для Park Model, ParkSerializer. Це змінює назву alternate_name на розташування.

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

__Позначення Джанго для обходу зовнішнього ключа також працює:

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

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

Однак це буде працювати лише для полів лише для читання.


Зараз цей виняток кидає AttributeError на об'єкт / ViewName / 'module' не має атрибута 'SerializerMethodField'
— Shoaib Ijaz,

1
Як би ця тренування зі створенням та редагуванням запитів?
— iankit

1
Рядок № 13 "Zen of Python": "Це повинен бути один - і бажано лише один - очевидний спосіб зробити це".
— iankit

14
Це не повинно бути прийнятою відповіддю. Подивіться наведене нижче, яке на момент написання цього повідомлення мало майже в 5 разів більше голосів.
— cderwin

6
Це погане рішення. sourceЗамість цього використовуйте кварг, як описано нижче.
— Патрік

215

У полях серіалізатора та серіалізаторах загалом є дуже приємна особливість, яка називається 'джерело', де ви можете вказати джерело даних із поля моделі.

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

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

Де serializers.SomeSerializerField можуть бути серіалізаторами.CharField, як передбачає ваша модель, але також можна в будь-якому іншому полі. Також ви можете замість цього поставити реляційні поля та інші серіалізатори, і це все одно буде працювати як шарм. тобто навіть якщо alternate_name було полем чужого ключа для іншої моделі.

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

Обидві відповіді неповні. У випадку із зовнішнім ключем цей метод передбачає, що при створенні нового парку у запиті POST потрібно вказати весь батьківський об’єкт (alternate_name) як дикт, що божевільно, оскільки батьківський об’єкт уже існує. Потрібно мати можливість згадувати іноземний екземпляр через його ідентифікатор.
— stelios

У моєму випадку (зовнішній ключ) я вирішив цю проблему за допомогою locations = serializers.PrimaryKeyRelatedField(source='alternate_name', queryset=AlternateName.objects.all()). Мабуть, також RelatedFieldможна використовувати.
— stelios

@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.