2017-07-01 99 views
0

请考虑此票证模型,其中两个字段(showseat)应该唯一。它还有一个布尔字段(paid)来表明票是否支付。检查是否存在具有唯一字段的对象,以在保存之前创建或删除

型号:

class Ticket(models.Model): 
    show = models.ForeignKey(Show) 
    seat = models.ForeignKey(Seat) 
    user = models.ForeignKey(User) 
    paid = models.BooleanField(default=False) 

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

这是客户端的数据

[ 
    {u'seat': 6, u'user': 3, u'show': 2}, 
    {u'seat': 7, u'user': 3, u'show': 2} 
] 

而且意见的例子:

def buy_ticket(request): 
    serialized = TicketSerializer(data=request.data, many=True) 
    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) 

我想要做的是检查是否有是提供数据的任何票(seatshow)。如果没有这样的票证,则创建一个新票据。否则,如果有票,则检查该票是否已支付。如果未付款,则删除该凭单并用新数据创建一个新凭单,否则会引发错误。

我试图在串行这样的方式,但我仍然得到一个唯一的错误:

class TicketSerializer(serializers.ModelSerializer): 
    class Meta: 
     model = Ticket 
     fields = '__all__' 

    def validate(self, data): 
     try: 
      ticket = Ticket.objects.get(seat=data['seat'], show=data['show']) 
      if not ticket.paid: 
       ticket.delete() 
       return data 
     except Ticket.DoesNotExist: 
      return data 
+0

可能不是你的唯一错误的根源,但我认为你在那里有一个竞争条件。你需要确保它被封装在一个事务中,或者实现某种在你的delete()和create()调用之间持续存在的锁定。 – whp

+0

@whp我很抱歉,我没有得到你。你能否再解释一下。谢谢。 – Aamu

+1

不要在序列化程序中执行此操作。这是模型管理员或视图的任务。串行器应该将模型转换成json,而不是做其他任何事情。 – Melvyn

回答

0

使用get_or_create

ticket, created = Ticket.objects.get_or_create(seat=data['seat'], show=data['show'], user=data['user']) 
if not created and not ticket.paid: 
    ticket.delete() 
return data 

你需要user,因为它是一个必填字段。

0

whp的建议和修改的The_Cthulhu_Kid答案,试试这个

from django.db import transaction 

class TicketSerializer(serializers.ModelSerializer): 
    class Meta: 
     model = Ticket 
     fields = '__all__' 

    def validate(self, data): 

     with transaction.atomic(): 
      ticket, created = Ticket.objects.get_or_create(seat=data['seat'], show=data['show'], user=data['user']) 
      if not created and not ticket.paid: 
       ticket.delete() 
      else: 
       raise ValidationError("Your error here") 
     return data 
+0

我应该在哪里调用上述交易代码? – Aamu

+0

我想你的表单验证。在你的'validate()'方法中。我应该编辑我的答案,包括其余的。 – zaidfazil

相关问题