Як змінити назву поля в 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.