Bagaimana mengubah nama bidang dalam Kerangka REST Django

98

Saya mencoba mengubah nama bidang Model di DRF Serializer seperti alias di SQL. Saya telah mencoba berbagai metode tetapi tidak berhasil.

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

Saya juga mencoba menambahkan alias di Django Queryset tetapi tidak dapat diubah.

Diperbarui

Ini adalah pengecualian yang saya hadapi

AttributeError pada / ViewName / objek 'module' tidak memiliki atribut 'Field'

Bagaimana saya bisa melakukan ini?

Shoaib Ijaz
sumber
1
Apakah Anda menggunakan penerapan serializers.SerializerMethodFieldpendekatan yang benar? Maksud saya ini: serializers.SerializerMethodField('get_location')dandef get_location(self, obj): ...
erthalion
Bisakah kita melihat impor serializers.py?
joerick
akan downvote pertanyaan karena OP menerima jawaban yang sebagian salah dan membingungkan daripada yang lebih baik di bawah ...
NeuronQ

Jawaban:

59

Anda dapat menggunakan serializers.SerializerMethodField:

Berikut adalah model Park, yang memiliki field name dan 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

Ini Serializer untuk Model Taman, ParkSerializer. Ini mengubah nama alternate_name menjadi lokasi.

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

Selain itu, Anda dapat menggunakan serializers.CharFielddengan sourceatribut:

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

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

__Notasi Django untuk melintasi kunci asing juga bekerja:

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

Prinsip yang sama berlaku jika Anda ingin mengubah jenis pengembalian di API, sehingga Anda dapat melakukannya serializers.DecimalField(source=...)dan jenis bidang lainnya juga.

Namun ini hanya akan berfungsi untuk bidang hanya baca.

erthalion
sumber
Sekarang pengecualian ini melempar AttributeError ke / ViewName / objek 'module' tidak memiliki atribut 'SerializerMethodField'
Shoaib Ijaz
1
Bagaimana latihan ini dengan membuat dan mengedit permintaan?
iankit
1
Baris no 13 dari 'Zen of Python': "Seharusnya ada satu - dan sebaiknya hanya satu - cara yang jelas untuk melakukannya."
iankit
14
Ini seharusnya bukan jawaban yang diterima. Lihat satu di bawah, yang memiliki suara positif hampir 5 kali lebih banyak pada saat saya menulis ini.
cderwin
6
Ini adalah solusi yang buruk. Gunakan sourcekwarg sebagai gantinya seperti yang dijelaskan di bawah ini.
Patrick
215

Ada fitur yang sangat bagus di bidang serializer dan serializers secara umum disebut 'sumber' di mana Anda dapat menentukan sumber data dari bidang model.

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

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

Di mana serializers.SomeSerializerField dapat menjadi serializers.CharField seperti yang disarankan model Anda, tetapi juga dapat oleh bidang lain. Anda juga dapat meletakkan bidang relasional dan penyambung lainnya sebagai gantinya dan ini akan tetap berfungsi seperti pesona. yaitu bahkan jika alternate_name adalah bidang kunci asing ke model lain.

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

Ini bekerja dengan pembuatan, penghapusan dan modifikasi jenis permintaan juga. Ini secara efektif membuat pemetaan satu-satu nama bidang di serializer dan nama bidang di model.

iankit
sumber
Saya setuju, itu sourcependekatan yang lebih umum. Tetapi Anda dapat melihat beberapa upaya untuk menggunakannya dalam pertanyaan, jadi jika Anda ingin menjawab seperti itu, Anda juga harus menjelaskan mengapa kode asli tidak berfungsi, bukan?
erthalion
Kode Anda akan berfungsi dengan baik .. selama permintaan adalah untuk daftar dan diambil
iankit
Kedua jawaban itu tidak lengkap. Dalam kasus kunci asing, metode ini menyiratkan bahwa saat membuat Park baru, Anda harus memberikan seluruh objek induk (alternate_name) sebagai perintah dalam permintaan POST Anda, yang tidak masuk akal karena objek induk sudah ada. Seseorang harus dapat menyebutkan contoh asing melalui id-nya.
stelios
Dalam kasus saya (kunci asing), saya memecahkan masalah ini dengan locations = serializers.PrimaryKeyRelatedField(source='alternate_name', queryset=AlternateName.objects.all()). Ternyata RelatedFieldbisa digunakan juga.
stelios
@chefarov source = 'new_name' adalah argumen umum yang dapat Anda berikan ke bidang serializer, relasi, dan pembuat serial terkait lainnya, dll. Tidak yakin mengapa Anda mengatakan jawabannya tidak lengkap.
iankit
15

Ini akan bekerja untuk operasi tulis juga

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

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