DRF中创建对象时如何优雅修改关联对象状态?
更规范的DRF实现:创建预约时修改书籍可用性
原代码的问题点
perform_create方法签名错误:DRF中该方法的参数是serializer而非request,原写法会触发报错- 冗余数据库查询:手动从
request.data提取ID查询书籍,完全可以直接利用已创建的Reservation实例关联的Book对象 - 未处理并发风险:多请求同时预约同一本书时,可能出现超卖问题
优化方案1:修正视图层逻辑(推荐)
直接借助序列化器创建好的Reservation实例操作关联Book,同时用原子事务保证数据一致性:
from django.db import transaction from rest_framework import viewsets class ReservationViewSet(viewsets.ModelViewSet): queryset = ReservationModel.objects.all() serializer_class = ReservationSerializer permission_classes = [] # 修正原代码拼写错误:permission_classess → permission_classes def perform_create(self, serializer): # 原子事务确保预约创建与书籍状态修改要么同时成功,要么同时回滚 with transaction.atomic(): reservation = serializer.save() # 直接通过关联对象获取Book,避免额外查询 book = reservation.book book.is_available = False book.save()
优化方案2:将逻辑内聚到序列化器
如果希望把业务逻辑封装在序列化层,可重写ReservationSerializer的create方法:
from django.db import transaction from rest_framework import serializers class ReservationSerializer(serializers.HyperlinkedModelSerializer): class Meta: model = ReservationModel fields = ["reserved_by", "book", "started_at", "valid_until"] def create(self, validated_data): with transaction.atomic(): reservation = super().create(validated_data) book = reservation.book book.is_available = False book.save() return reservation
额外优化建议
- 封装模型层逻辑:在
BookModel中添加方法封装状态修改,进一步解耦业务代码
之后在视图或序列化器中直接调用class BookModel(models.Model): # ... 原有字段 def mark_as_unavailable(self): self.is_available = False self.save()book.mark_as_unavailable()即可 - 修正原代码中
permission_classess的拼写错误,正确写法为permission_classes
内容的提问来源于stack exchange,提问作者dawid.pawlowski
相关产品推荐
相关产品推荐

