ข้อมูลอัปเดต Django Rest Framework ก่อนที่จะทำให้เป็นอนุกรม

ฉันต้องการให้ผู้ใช้ทุกคนสามารถสร้างผลิตภัณฑ์ของตนเองด้วย RESTful API ของฉัน เพื่อจุดประสงค์นี้ ฉันได้สร้างมุมมองที่สืบทอด ListCreateAPIView ปัญหาคือผู้ใช้ควรสร้างเฉพาะผลิตภัณฑ์ที่เขา/เธอเป็นเจ้าของ ดังนั้นเมื่อมีการสร้างอินสแตนซ์ของโมเดลผลิตภัณฑ์ ฉันต้องการให้เจ้าของฟิลด์สอดคล้องกับผู้ใช้ที่ได้รับการตรวจสอบสิทธิ์

นี่คือรุ่นผลิตภัณฑ์ของฉัน

class Product(models.Model):
    owner = models.ForeignKey(User)
    name = models.CharField(max_length=30)

เห็นได้ชัดว่าซีเรียลไลเซอร์ของฉันคือ:

class ProductSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Product

และมุมมองของฉัน:

class ProductView(generics.ListCreateAPIView):
    queryset = models.Product.objects.all()
    serializer_class = serializers.ProductSerializer
    permission_classes = (IsAuthenticatedOrReadOnly,)

    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        #serializer.initial_data['owners'] = models.Person.objects.get(user__email=request.user).user_id
        self.perform_create(serializer)
        headers = self.get_success_headers(serializer.data)

        return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)

อย่างที่คุณเห็น ฉันพยายามแก้ไข "initial_data" แต่เป็น QueryDict ซึ่งไม่เปลี่ยนรูป อีกทางเลือกหนึ่งคือการแปลงมันเป็น Python dict แล้วเพิ่มค่า "owner" แต่เมื่อทำเช่นนั้นฉันจะได้รับทุกค่าเป็นรายการ (เช่น {'name': ['MyName']}) ดังนั้นมันจึงเป็นอย่างมาก วิธีแก้ปัญหาที่น่าเกลียด ฉันคิดว่ามันควรจะเป็นวิธีแก้ปัญหาที่ตรงไปตรงมากว่านี้


person Andres Espinosa    schedule 03.07.2016    source แหล่งที่มา


คำตอบ (3)


คุณสามารถแทนที่ perform_create() และส่งผ่านผู้ใช้ปัจจุบันเป็น owner จากนั้น เมื่ออินสแตนซ์ Product จะถูกสร้างขึ้น ฟิลด์ owner จะถูกบันทึกด้วยค่าผู้ใช้ปัจจุบัน

class ProductView(generics.ListCreateAPIView):
    queryset = models.Product.objects.all()
    serializer_class = serializers.ProductSerializer
    permission_classes = (IsAuthenticatedOrReadOnly,)

    def perform_create(self, serializer):
        serializer.save(owner=self.request.user) # pass the current user as the 'owner'

นอกจากนี้ คุณควร กำหนดฟิลด์ owner ในซีเรียลไลเซอร์ของคุณเป็น _7. จากนั้นจะไม่จำเป็นต้องมีฟิลด์นี้ในระหว่างการดีซีเรียลไลซ์ แต่ฟิลด์นี้จะรวมอยู่ในเอาต์พุตของการทำให้เป็นอนุกรม

 class ProductSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Product
        extra_kwargs = {'owner': {'read_only':True}} # set 'owner' as read-only field 
person Rahul Gupta    schedule 03.07.2016
comment
ปัญหาก็คือว่าฟังก์ชัน act_create ถูกเรียกหลังจากการดำเนินการ is_valid() และซีเรียลไลเซอร์จะไม่ถูกต้องหากไม่มีฟิลด์เจ้าของ ดังนั้นฟังก์ชัน create จะเพิ่มข้อยกเว้นก่อนที่ดำเนินการ act_create - person Andres Espinosa; 03.07.2016
comment
คุณสามารถกำหนดฟิลด์ owner เป็น read_only ในซีเรียลไลเซอร์ของคุณได้ จากนั้นจะไม่จำเป็นต้องใช้ในระหว่างการดีซีเรียลไลซ์ แต่จะถูกส่งกลับในเอาต์พุตเสมอเมื่อซีเรียลไลซ์ - person Rahul Gupta; 03.07.2016

วิธีแก้ปัญหาง่ายๆด้านล่าง owner จะไม่ปรากฏให้เห็นในคำขอ GET/POST/PUT ฯลฯ แต่จะถูกกำหนดให้กับผู้ใช้ที่ได้รับการรับรองความถูกต้องในปัจจุบันโดยอัตโนมัติ

from rest_framework.serializers import (CurrentUserDefault, HiddenField,
                                        ModelSerializer)

class ProductSerializer(ModelSerializer):
    owner = HiddenField(default=CurrentUserDefault())

    class Meta:
        model = models.Product
person dikamilo    schedule 04.07.2016
comment
มันเป็นผลงานที่ค่อนข้างดี ขอบคุณ. - person ishak O.; 09.02.2021

คุณสามารถส่งข้อมูลเริ่มต้นในมุมมอง จากนั้นเขียนค่าเริ่มต้นใหม่ในซีเรียลไลเซอร์

มุมมอง.py

class ItemListCreateView(ListCreateAPIView):

    def get_serializer_context(self):
        return {"delivery_request": self.kwargs['req_pk']}

serializers.py

class ItemCreateSerializer(ModelSerializer):
    delivery_request = CharField(default='')

    def validate_delivery_request(self, value):
        try:
            value = DeliveryRequest.objects.get(
                id=self.context["delivery_request"])
        except DeliveryRequest.DoesNotExist:
            raise ValidationError(
                self.Meta.error_messages['delivery_request_not_found'])
        return value

ป.ล. มันมีประโยชน์เมื่อคุณต้องการเติมข้อมูลที่ไม่ใช่ Null จาก url เป็นต้น

person Artem Bernatskyi    schedule 12.03.2018