เมื่อใดควรใช้ Serializer ของ create () และสร้าง () perform_create () ของ ModelViewset


103

ฉันต้องการชี้แจงเอกสารที่ระบุdjango-rest-frameworkเกี่ยวกับการสร้างวัตถุแบบจำลอง จนถึงตอนนี้ฉันพบว่ามี 3 แนวทางในการจัดการกับเหตุการณ์ดังกล่าว

  1. create()วิธีการของ Serializer นี่คือเอกสาร

    class CommentSerializer(serializers.Serializer):
    
        def create(self, validated_data):
            return Comment.objects.create(**validated_data)
    
  2. create()วิธีModelViewset เอกสารประกอบ

    class AccountViewSet(viewsets.ModelViewSet):
    
        queryset = Account.objects.all()
        serializer_class = AccountSerializer
        permission_classes = [IsAccountAdminOrReadOnly]
    
  3. perform_create()วิธีModelViewset เอกสารประกอบ

    class SnippetViewSet(viewsets.ModelViewSet):
    
        def perform_create(self, serializer):
            serializer.save(owner=self.request.user)
    

แนวทางทั้งสามนี้มีความสำคัญขึ้นอยู่กับสภาพแวดล้อมการใช้งานของคุณ

แต่เราต้องใช้แต่ละcreate() / perform_create()ฟังก์ชันเมื่อใด ??. บนมืออื่น ๆ ผมพบว่าบัญชีของบางอย่างที่สองสร้างวิธีการที่ถูกเรียกร้องให้มีการโพสต์คำขอเดียว modelviewset ของcreate()และของ create()serializer

หวังว่าทุกคนจะแบ่งปันความรู้เพื่ออธิบายและสิ่งนี้จะเป็นประโยชน์อย่างมากในกระบวนการพัฒนาของฉัน

คำตอบ:


132
  1. คุณจะใช้create(self, validated_data)เพื่อเพิ่มรายละเอียดพิเศษใด ๆ ลงในออบเจ็กต์ก่อนที่จะบันทึกและ "prod" ค่าลงในฟิลด์แต่ละรุ่นเช่นเดียวกับที่**validated_dataทำ ตามหลักการแล้วคุณต้องการทำรูปแบบ "การแยง" นี้ในสถานที่เดียวเท่านั้นดังนั้นcreateวิธีการของคุณCommentSerializerจึงเป็นสถานที่ที่ดีที่สุด นอกจากนี้คุณอาจต้องการเรียก apis ภายนอกเพื่อสร้างบัญชีผู้ใช้ที่ด้านข้างก่อนบันทึกบัญชีของคุณลงในฐานข้อมูลของคุณเอง คุณควรใช้นี้ฟังก์ชั่นร่วมกับcreate ModelViewSetคิดเสมอว่า - "Thin views, Thick serializers"

ตัวอย่าง:

def create(self, validated_data):
    email = validated_data.get("email", None)
    validated.pop("email") 
    # Now you have a clean valid email string 
    # You might want to call an external API or modify another table
    # (eg. keep track of number of accounts registered.) or even
    # make changes to the email format.

    # Once you are done, create the instance with the validated data
    return models.YourModel.objects.create(email=email, **validated_data)
  1. create(self, request, *args, **kwargs)ฟังก์ชั่นในModelViewSetถูกกำหนดไว้ในชั้นเรียนซึ่งเป็นแม่ของCreateModelMixin หน้าที่หลักมีดังนี้:ModelViewSetCreateModelMixin

    from rest_framework import status
    from rest_framework.response import Response
    
    
    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        self.perform_create(serializer)
        headers = self.get_success_headers(serializer.data)
        return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
    
    def perform_create(self, serializer):
        serializer.save()
    

อย่างที่คุณเห็นcreateฟังก์ชั่นด้านบนดูแลการเรียกตรวจสอบความถูกต้องบนซีเรียลไลเซอร์ของคุณและสร้างการตอบสนองที่ถูกต้อง ความงามที่อยู่เบื้องหลังสิ่งนี้คือตอนนี้คุณสามารถแยกตรรกะของแอปพลิเคชันของคุณและไม่ต้องกังวลกับตัวเองเกี่ยวกับการเรียกตรวจสอบความถูกต้องทางโลกและทางซ้ำและการจัดการผลลัพธ์การตอบสนอง :) สิ่งนี้ทำงานได้ค่อนข้างดีในการเชื่อมต่อกับcreate(self, validated_data)found ใน serializer (ซึ่งตรรกะของแอปพลิเคชันเฉพาะของคุณอาจอยู่)

  1. ตอนนี้คุณอาจถามว่าทำไมเราถึงมีperform_create(self, serializer)ฟังก์ชันแยกกันด้วยรหัสเพียงบรรทัดเดียว!?!? เหตุผลหลักที่อยู่เบื้องหลังนี้คือเพื่อให้สามารถปรับแต่งได้เมื่อเรียกใช้saveฟังก์ชัน คุณอาจต้องการจัดหาข้อมูลเพิ่มเติมก่อนโทรsave (เช่นserializer.save(owner=self.request.user)และถ้าเราไม่มีperform_create(self, serializer)คุณจะต้องลบล้างcreate(self, request, *args, **kwargs)และนั่นก็เอาชนะจุดประสงค์ของการให้มิกซ์อินทำงานหนักและน่าเบื่อ

หวังว่านี่จะช่วยได้!


ไฮ! ขอบคุณสำหรับการแบ่งปันความรู้ของคุณ! เกี่ยวกับcreate(self, validated_data)serializer หมายความว่ามันเน้นตรรกะการตรวจสอบข้อมูล? และยิ่งไปกว่านั้นมันสามารถช่วยส่งคืนข้อมูลของ serializer ที่ระบุกลับไปที่การตอบสนองได้ใช่ไหม
Roel

1
ไม่ถึงตอนนี้คุณได้ผ่านการตรวจสอบความถูกต้องของคุณทั้งหมดแล้ว ฉันกำลังพูดถึงวิธีที่คุณอาจต้องการปรับแต่งข้อมูลที่ผ่านการตรวจสอบก่อนที่จะบันทึกลงในฐานข้อมูล ฉันจะทำตัวอย่างในคำตอบของฉัน
Apoorv Kansal

1
ไม่ต้องกังวล - เพิ่งเพิ่มตัวอย่างเพื่อให้บริบทมากขึ้น
Apoorv Kansal

1
ใช่บรรทัดสุดท้ายที่จะบันทึกวัตถุของคุณลงในฐานข้อมูล
Apoorv Kansal

1
ดังนั้นcreateฟังก์ชั่นใน serializer เองเท่านั้นserializer.save()เรียกว่าเมื่อคุณทำ ในของคุณcreate(self, request)ภายในฟังก์ชัน ( AccountViewSet) คุณจะไม่ได้เรียกร้องที่ทุกคนและดังนั้นการสร้างเพียงตัวอย่างที่เกิดขึ้นกับสายนี้:serializer.save() Account.objects.create_user(**serializer.validated_data)
Apoorv Kansal
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.