gpt4 book ai didi

Django @transaction.atomic() 防止并发创建对象

转载 作者:行者123 更新时间:2023-12-04 20:29:35 25 4
gpt4 key购买 nike

我有一个票证模型和它的票证序列化器。票证型号有bought和一个 booked_at field 。还有一个 unique_together表演和座位的属性。

class Ticket(models.Model):
show = models.ForeignKey(Show, on_delete=models.CASCADE)
seat = models.ForeignKey(Seat, on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE)
booked_at = models.DateTimeField(default=timezone.now)
bought = models.BooleanField(default=False)

class Meta:
unique_together = ('show', 'seat')
  • 在票序列化器上,验证序列化器检查是否有任何具有所需座位的票并显示
  • 如果有票,则它检查票是否已购买。
  • 如果它被购买,那么它会引发错误。
  • 如果没有购买,请检查是否在 5 分钟内预订了机票。
  • 如果它在 5 分钟内预订,则引发错误。
  • 否则如果预订时间超过5分钟,则删除旧票并返回有效。
  • 如果没有票则返回有效

  • 票证序列化器:
    class TicketSerializer(serializers.Serializer):
    seat = serializers.PrimaryKeyRelatedField(queryset=Seat.objects.all())
    show = serializers.PrimaryKeyRelatedField(queryset=Show.objects.all())
    user = serializers.PrimaryKeyRelatedField(queryset=User.objects.all())
    bought = serializers.BooleanField(default=False)

    def validate(self, attrs):
    if attrs['seat']:
    try:
    ticket = Ticket.objects.get(show=attrs['show'], seat=seat)
    if not ticket.bought:
    if ticket.booked_at < timezone.now() - datetime.timedelta(minutes=5):
    # ticket booked crossed the deadline
    ticket.delete()
    return attrs
    else:
    # ticket in 5 mins range
    raise serializers.ValidationError("Ticket with same show and seat exists.")
    else:
    raise serializers.ValidationError("Ticket with same show and seat exists.")
    except Ticket.DoesNotExist:
    return attrs
    else:
    raise serializers.ValidationError("No seat value provided.")

    在 View 上,我正在使用 @transaction.atomic()确保仅在所有票证都有效时才创建票证,或者如果无效则不创建任何票证。
    @transaction.atomic()
    @list_route(
    methods=['POST'],
    permission_classes=[IsAuthenticated],
    url_path='book-tickets-by-show/(?P<show_id>[0-9]+)'
    )
    def book_tickets_by_show(self, request, show_id=None):
    try:
    show = Show.objects.get(id=show_id)
    user = request.user
    ...
    ...
    data_list = [...]
    with transaction.atomic():
    try:
    serializer = TicketSerializer(data=data_list, many=True)
    if serializer.is_valid():
    serializer.save()
    ....
    return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
    except (Seat.DoesNotExist, ValueError, ConnectionError) as e:
    return Response({'detail': str(e)}, status=status.HTTP_400_BAD_REQUEST)
    except (Show.DoesNotExist, IntegrityError) as e:
    return Response({'detail': str(e)}, status=status.HTTP_400_BAD_REQUEST)

    我想知道的是,它是否有助于防止调用多个请求为同一座位创建票证?

    假设,用户 A 想要预订座位 5,6 的票。用户 B 想订 3、6 号座位的票,另一个用户 C 想订 2、3、4、5、6 号座位的票。

    上述方法是否会阻止所有用户为其各自的座位预订门票,而只为一个用户(可能是第一个交易的用户)创建门票?或者如果有更好的方法,那么你能告诉我怎么做吗?我希望我很清楚。如果没有请询问。

    最佳答案

    Will it help in preventing when more than one requests are called for creating the ticket/s for same seat/s.



    是的,它会。 unique_together约束加 transaction.atomic()将确保您不能为同一个座位/演出创建两张票。

    也就是说,您当前的方法存在几个问题:
  • 我认为没有必要包装整个 View 以及在 atomic() 中进行保存的部分- 您不需要同时执行这两项操作,并且将整个 View 包装在事务中会带来性能成本。包装 serializer.save()在一个交易中应该就足够了。
  • 不建议在事务中捕获异常 - 参见 the warning in the documentation .通常最好在尽可能接近可以生成异常的代码处捕获异常,以避免混淆。我建议将代码重构为这样的东西。
    try:
    show = Show.objects.get(id=show_id)
    # Catch this specific exception where it happens, rather than at the bottom.
    except Show.DoesNotExist as e:
    return Response({'detail': str(e)}

    user = request.user
    ...
    ...
    data_list = [...]

    try:
    serializer = TicketSerializer(data=data_list, many=True)
    if serializer.is_valid():
    try:
    # Note - this is now *inside* a try block, not outside
    with transaction.atomic():
    serializer.save()
    ....
    except IntegrityError as e:
    return Response({'detail': str(e), status=status.HTTP_400_BAD_REQUEST}

    return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
    # Retained from your code - althought I am not sure how you would
    # end up with ever get a Seat.DoesNotExist or ValueError error here
    # Would be better to catch them in the place they can occur.
    except (Seat.DoesNotExist, ValueError, ConnectionError) as e:
    return Response({'detail': str(e)}, status=status.HTTP_400_BAD_REQUEST)
  • 关于Django @transaction.atomic() 防止并发创建对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49905035/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com