簡體   English   中英

在 Django 和 Django Rest Framework 中使用一個請求創建多個對象

[英]Creating multiple objects with one request in Django and Django Rest Framework

我使用 Django 作為后端服務器,使用 Vue.js 作為前端電影應用程序。

我有一個票證模型

class MovieTicket(models.Model):
    show = models.ForeignKey(Show)
    seat = models.ForeignKey(Seat)
    user = models.ForeignKey(User)
    purchased_at = models.DateTimeField(default=timezone.now)
    qrcode = models.ImageField(upload_to='qrcode', blank=True, null=True)
    qrcode_data = models.CharField(max_length=255, unique=True, blank=True)

    class Meta:
        unique_together = ('show', 'seat')

及其相關的序列化程序

class MovieTicketSerializer(serializers.ModelSerializer):
    class Meta:
        model = MovieTicket
        fields = '__all__'

要購買新票,有一個映射到此 url http://dev.site.com/api/movies/buy-ticket/的視圖

@api_view(['POST'])
@permission_classes([IsAuthenticated])
def buy_ticket(request):
    serialized = MovieTicketSerializer(data=request.data)
    if serialized.is_valid():
        serialized.save()
        return Response(serialized.data, status=status.HTTP_201_CREATED)
    return Response(serialized._errors, status=status.HTTP_400_BAD_REQUEST)

現在從前端(Vue.js)我可以創建一個新的電影票:

const formBody = {
    show: this.$store.state.showSelected.showTime.id,
    user: this.$store.state.user.id,

    // selectedSeats is an array of seats that have been selected by the user. Here I am passing the first seat object.
    seat: this.$store.state.selectedSeats[0].seat.id
};

this.$http.post("http://dev.site.com/api/movies/buy-ticket/", formBody)
    .then(function (response) {
        console.log(response.data);
    })
    .catch(function (response) {
        console.log(response);
    });
return;

如果表單有效,這將創建一個新的 MovieTicket 對象,否則顯示錯誤。

現在,假設如果用戶選擇了多個座位,我可以遍歷每個selectedSeats數組並在客戶端獲取座位 ID。 並發布這樣的內容:

{
    "purchased_at": null,
    "qrcode": null,
    "qrcode_data": "",
    "show": 11,
    "seat": [
        106,
        219
    ],
    "user": 34
}

但是我感到困惑的是,如果 Django rest 框架每個請求只接受一個座位並相應地顯示錯誤,我該如何傳遞多個seat.id 如果票可用或不可用,則表示顯示錯誤,如果可用,則為該演出座位創建電影票。

使用 many=True 初始化序列化程序

在您的實現中,這很容易實現:

serialized = MovieTicketSerializer(data=request.data, many=True)

數據不是單個對象,而是一組對象。

您的信息表明您需要轉換 request.data 以制作這些多個對象(所有相同的數據只是不同的座位號)。 對?

無論如何:

請參閱: 如何使用 Django Rest Framework 創建多個模型實例?

編輯:

這里是 drf 文檔中的信息: http : //www.django-rest-framework.org/api-guide/serializers/#dealing-with-multiple-objects

(強烈建議在編寫第一個真正的實現之前,從上到下閱讀 drf 文檔並嘗試使用它。有很多方法可以使用 drf,了解所有這些會導致更好的決策)

編輯 2(問題更新后):

您可以從客戶端發送此 JSON(見下文),或從客戶端在調用MovieTicketSerializer(...,many=True)之前在您的buy_ticket(request)方法中發送的當前 JSON 創建此格式:

[
    {
        "purchased_at": null,
        "qrcode": null,
        "qrcode_data": "",
        "show": 11,
        "seat": 106,
        "user": 34
    },
    {
        "purchased_at": null,
        "qrcode": null,
        "qrcode_data": "",
        "show": 11,
        "seat": 219,
        "user": 34
    }
]

這個答案是這個問題的一個很好的解決方案:

您可以簡單地覆蓋get_serializer中的get_serializer方法,並將many=True傳遞到基礎視圖的get_serializer中,如下所示:

    class SomeAPIView(CreateAPIView):
        queryset = SomeModel.objects.all()
        serializer_class = SomeSerializer

        def get_serializer(self, instance=None, data=None, many=False, partial=False):
            if data is not None:
                data.is_valid(raise_exception=True)
                return super(SomeAPIView, self).get_serializer(instance=instance, data=data, many=True, partial=partial)
            else:
                return super(SomeAPIView, self).get_serializer(instance=instance, many=True, partial=partial)

如原始帖子評論中所述,在將data關鍵字傳遞給序列化程序的情況下,您還必須調用data.is_valid()

您可以在查看功能中查看座位數並創建一張或多張票:

@api_view(['POST'])
@permission_classes([IsAuthenticated])
def buy_ticket(request):
    # Check if seats is a list
    if isinstance(request.data['seat'], list):
        seats = request.data.pop('seat')
        models = []
        for seat in seats:
            # validate each model with one seat at a time
            request.data['seat'] = seat
            serializer = MovieTicketSerializer(data=request.data)
            serializer.is_valid(raise_exception=True)
            models.append(serializer)
        # Save it only after all seats are valid. 
        # To avoid situations when one seat has wrong id 
        # And you already save previous
        saved_models = [model.save() for model in models]
        result_serializer = MovieTicketSerializer(saved_models, many=True)
        # Return list of tickets
        return Response(result_serializer.data)
    # Save ticket as usual
    serializer = MovieTicketSerializer(data=request.data)
    serializer.is_valid(raise_exception=True)
    serializer.save()
    return Response(serializer.data)

它會起作用,但老實說,這真是一團糟。 您可以在不同的功能中移動用於創建座位的邏輯,使其看起來更好。

如果您希望用戶能夠為一張票選擇多個座位,那么刪除SeatMovieTicket的一對一映射並創建多一關系可能是個好主意。 像這樣:

序列化器:

class SeatSerializer(serializers.ModelSerializer):
    class Meta:
        model = Seat

class MovieTicketSerializer(serializers.ModelSerializer):
    seats = SeatSerializer(many=True)
    class Meta:
        model = MovieTicket
        fields = '__all__'

    def create(self, vlaidated_data):
        seats = validated_data.pop('seats')
        instance = MovieTicket.objects.create(
            **validated_data)

        for seat in seats:
            Seat.objects.create(
                movieticket=instance, **seats)

        return instance

模型應該如下所示:

class MovieTicket(models.Model):
    show = models.ForeignKey(Show)
    user = models.ForeignKey(User)
    purchased_at = models.DateTimeField(default=timezone.now)
    qrcode = models.ImageField(upload_to='qrcode', blank=True, null=True)
    qrcode_data = models.CharField(max_length=255, unique=True, blank=True)

class Seat(models.Model):
    movieticket = ForeignKey(
        MovieTicket, related_name="movieticket")

    # ... other fields.

這將允許您在請求中傳遞一組“座位”。

如果您不介意在 django 項目中添加另一個應用程序,您可以嘗試使用django-rest-framework-bulk ,如果沒有,您可以檢查代碼並查看它是如何實現的。

如果您使用此應用程序,您將能夠通過在 POST 請求中發送元素列表來執行批量創建操作。

例如:

[{'name': 'Jane'}, {'name': 'John'}, {'name': 'Johny'}]

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM