วิธีเปลี่ยนชื่อฟิลด์ใน Django REST Framework


98

ฉันพยายามเปลี่ยนชื่อฟิลด์ Model ใน 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 แล้ว แต่ไม่สามารถเปลี่ยนได้

อัปเดตแล้ว

นี่คือข้อยกเว้นที่ฉันกำลังเผชิญ

AttributeError ที่ / ViewName / 'module' object ไม่มีแอตทริบิวต์ '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

นี่คือ Serializerสำหรับ Park Model, 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'
Shoaib Ijaz

1
การออกกำลังกายนี้จะสร้างและแก้ไขคำขอได้อย่างไร?
iankit

1
บรรทัดที่ 13 ของ 'Zen of Python': "ควรมีวิธีเดียว - และควรมีเพียงวิธีเดียวเท่านั้นที่จะทำได้"
iankit

14
นี่ไม่ควรเป็นคำตอบที่ยอมรับได้ ดูด้านล่างนี้ซึ่งมีการโหวตเพิ่มขึ้นเกือบ 5 เท่าในขณะที่ฉันเขียนสิ่งนี้
cderwin

6
นี่เป็นทางออกที่ไม่ดี ใช้sourcekwarg แทนตามที่อธิบายไว้ด้านล่าง
Patrick

215

มีคุณสมบัติที่ดีมากในฟิลด์ serializer และ serializers โดยทั่วไปเรียกว่า 'source' ซึ่งคุณสามารถระบุแหล่งที่มาของข้อมูลจากฟิลด์ model

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

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

โดยที่ serializers.SerializerField สามารถเป็น 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

สิ่งนี้ใช้ได้กับการสร้างการลบและการแก้ไขประเภทคำขอด้วย สร้างการแมปชื่อเขตข้อมูลแบบตัวต่อตัวใน serializer และชื่อฟิลด์ในโมเดลได้อย่างมีประสิทธิภาพ


ฉันเห็นด้วยนั่นsourceเป็นแนวทางทั่วไป แต่คุณสามารถเห็นความพยายามในการใช้งานไม่กี่ครั้งในคำถามดังนั้นหากคุณต้องการตอบแบบนั้นคุณควรระบุให้ชัดเจนว่าเหตุใดโค้ดต้นฉบับจึงไม่ทำงานใช่หรือไม่
erthalion

รหัสของคุณจะใช้งานได้ดี .. ตราบเท่าที่มีการร้องขอรายการและเรียกคืน
iankit

คำตอบทั้งสองไม่สมบูรณ์ ในกรณีของคีย์ต่างประเทศวิธีนี้หมายความว่าเมื่อสร้างพาร์ใหม่คุณต้องให้อ็อบเจ็กต์พาเรนต์ทั้งหมด (alternate_name) เป็นคำสั่งในคำขอ POST ของคุณซึ่งเป็นเรื่องบ้าเพราะมีอ็อบเจ็กต์พาเรนต์อยู่แล้ว หนึ่งควรสามารถพูดถึงอินสแตนซ์ต่างประเทศผ่านทาง id
stelios

ในกรณีของฉัน (คีย์ต่างประเทศ) ฉันแก้ไขปัญหานี้ด้วยlocations = serializers.PrimaryKeyRelatedField(source='alternate_name', queryset=AlternateName.objects.all()). เห็นได้ชัดว่าRelatedFieldสามารถใช้ได้เช่นกัน
stelios

@chefarov source = 'new_name' เป็นอาร์กิวเมนต์ทั่วไปที่คุณสามารถกำหนดให้กับฟิลด์ serializer ความสัมพันธ์และ serializers อื่น ๆ ที่เกี่ยวข้อง ฯลฯ ไม่แน่ใจว่าทำไมคุณถึงบอกว่าคำตอบไม่สมบูรณ์
iankit

15

สิ่งนี้จะใช้ได้กับการดำเนินการเขียนด้วย

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

    class Meta:
        model = Park
        fields = ('id', 'name', 'location')
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.