我使用Django作为后端服务器,使用Vue.js作为前端电影应用。
我有一个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')
及其相关的Serializer
class MovieTicketSerializer(serializers.ModelSerializer):
class Meta:
model = MovieTicket
fields = '__all__'
要购买新的Ticket,会有一个映射到此网址的视图 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休息框架只接受每个请求一个席位并相应地显示错误,我怎么能传递多个seat.id
?如果故障单可用,则显示错误,以及是否为该show-seat创建电影票。
答案 0 :(得分:11)
使用many = True
初始化序列化程序在您的实施中,这很容易实现:
serialized = MovieTicketSerializer(data=request.data, many=True)
数据不是单个对象,而是一个对象数组。
您的信息提示您需要转换request.data以生成这些多个对象(所有相同的数据只是不同的座位号)。正确?
反正:
请参阅:How do I create multiple model instances with Django Rest Framework?
编辑:
这里是drf docu中的信息:http://www.django-rest-framework.org/api-guide/serializers/#dealing-with-multiple-objects
(强烈建议在编写第一个真正的实现之前,从上到下阅读drf文档,然后再玩它。有很多方法可以使用drf,并且知道所有这些都会导致更好的决策)
编辑2(问题更新后):
您可以从客户端发送此JSON(请参阅下文),或者在您致电buy_ticket(request)
之前,使用MovieTicketSerializer(...,many=True)
方法中客户端发送的当前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
}
]
答案 1 :(得分:2)
您可以查看视图功能中的座位数,并创建一个或多个票证:
@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)
return Response(serializer.data)
它会起作用但老实说它真是一团糟。您可以在不同的功能中移动创建座位的逻辑,它看起来会更好。
答案 2 :(得分:0)
如果您希望用户能够为一个故障单选择多个席位,则最好删除Seat
和MovieTicket
的一对一映射,并创建多个席位关系。像这样:
串行器:
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.
然后,这将允许您传递一系列席位'在请求中。
答案 3 :(得分:0)
如果您不介意在django项目中添加其他应用,可以尝试使用django-rest-framework-bulk,否则可以查看代码并查看其实现方式。
如果您使用此应用程序,则可以通过在POST请求中发送元素列表来执行批量创建操作。
e.g:
[{'name': 'Jane'}, {'name': 'John'}, {'name': 'Johny'}]
答案 4 :(得分:0)
This answer是解决这个问题的一个非常好的解决方案:
您只需覆盖APIView中的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):
return super(SomeAPIView, self).get_serializer(instance=instance, data=data, many=True, partial=partial)