在Django和Django Rest Framework中使用一个请求创建多个对象

Aam*_*amu 17 django django-rest-framework

我使用Django作为后端服务器,使用Vue.js作为前端Movie应用程序.

我有一个Ticket模型

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')
Run Code Online (Sandbox Code Playgroud)

和它相关的Serializer

class MovieTicketSerializer(serializers.ModelSerializer):
    class Meta:
        model = MovieTicket
        fields = '__all__'
Run Code Online (Sandbox Code Playgroud)

要购买新的Ticket,有一个视图映射到此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)
Run Code Online (Sandbox Code Playgroud)

现在从前端(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;
Run Code Online (Sandbox Code Playgroud)

如果表单有效,这将创建一个新的MovieTicket对象,否则显示错误/ s.

现在,假设用户选择了多个席位,我可以遍历每个selectedSeats阵列并获得客户端的座位ID.并发布这样的东西:

{
    "purchased_at": null,
    "qrcode": null,
    "qrcode_data": "",
    "show": 11,
    "seat": [
        106,
        219
    ],
    "user": 34
}
Run Code Online (Sandbox Code Playgroud)

但令我困惑的是,seat.id如果Django休息框架只接受每个请求一个席位并相应地显示错误,我怎么能传递多个?如果故障单可用,则显示错误,以及是否为该show-seat创建可用的电影票证.

fet*_*zig 14

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

在您的实现中,这很容易实现:

serialized = MovieTicketSerializer(data=request.data, many=True)
Run Code Online (Sandbox Code Playgroud)

数据不是单个对象,而是一个对象数组.

您的信息提示您需要转换request.data以生成这些多个对象(所有相同的数据只是不同的座位号).对?

无论如何:

请参阅:如何使用Django Rest Framework创建多个模型实例?

编辑:

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

(强烈建议在编写第一个真正的实现之前,从上到下阅读drf文档并只是玩它.有很多方法可以使用drf,并且知道所有这些都会导致更好的决策)

编辑2(问题更新后):

您可以从客户端发送此JSON(请参阅下文),或者buy_ticket(request)在调用之前从客户端在您的方法中发送的当前JSON创建此格式MovieTicketSerializer(...,many=True):

[
    {
        "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
    }
]
Run Code Online (Sandbox Code Playgroud)


Bla*_*g23 6

这个答案是这个问题的一个很好的解决方案:

你可以简单地覆盖get_serializer法在APIView并传递many=Trueget_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)
Run Code Online (Sandbox Code Playgroud)

如原始帖子评论中所述,您还必须data.is_valid()在将data关键字传递给序列化程序的情况下调用。


Iva*_*kin 5

您可以在查看功能中查看座位数并创建一张或多张票:

@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)
Run Code Online (Sandbox Code Playgroud)

它会起作用,但老实说,这真是一团糟。您可以在不同的功能中移动用于创建座位的逻辑,使其看起来更好。