Aam*_*amu 5 django django-database
我有一个票模型,它的票序列化器.票证模型有一个bought和一个booked_at字段.还有unique_togethershow和seat 的属性.
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')
Run Code Online (Sandbox Code Playgroud)
TicketSerializer:
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.")
Run Code Online (Sandbox Code Playgroud)
在视图中,我@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)
Run Code Online (Sandbox Code Playgroud)
我想知道的是,它有助于防止在为同一个席位创建多个请求时创建机票/ s?
假设,用户A想要预订座位5,6的票.用户B想要预订座位3,6的票,而另一个用户C想要预订座位2,3,4,5,6的票.
上述方法是否会阻止为所有用户预订各自座位的票证,并且只为一个用户创建票证(可能是谁的交易是第一个)?或者,如果有更好的方法,那么请你告诉我如何.我希望我很清楚.如果没有,请问.
它是否有助于防止调用多个请求来为同一座位创建门票?
是的,它会。unique_together加号约束将transaction.atomic()确保您无法为同一座位/演出创建两张门票。
也就是说,您当前的方法存在几个问题:
我认为没有必要包装整个视图以及进行节省的部分atomic()- 您不需要同时执行这两项操作,并且将整个视图包装在事务中会带来性能成本。将其包装serializer.save()在事务中应该就足够了。
不建议在事务中捕获异常 - 请参阅文档中的警告。通常,最好在尽可能接近生成异常的代码处捕获异常,以避免混淆。我建议将代码重构为这样的内容。
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)
Run Code Online (Sandbox Code Playgroud)| 归档时间: |
|
| 查看次数: |
747 次 |
| 最近记录: |