我正在构建一个像Udemy这样的后端系统,在这个Cart API中,我试图更新一个caritem对象(一个学生想要添加另一门课程而不是这门课程),所以我想更改caritem中的课程并更改total_price购物车。发生的情况是,当我更新课程字段时,它返回 HTTP_200_OK 响应状态,但响应正文是更新前完全相同的对象的 JSON 对象,并且该对象未更新
模型.py
class Cart(models.Model):
id = models.UUIDField(primary_key=True, default=uuid4)
student = models.OneToOneField(
User, on_delete=models.CASCADE, related_name='cart')
total_price = models.IntegerField(default=0)
class CartItem(models.Model):
cart = models.ForeignKey(
Cart, on_delete=models.CASCADE, related_name='items')
course = models.ForeignKey(Course, on_delete=models.CASCADE)
views.py
class CartItemViewSet(ModelViewSet):
http_method_names = ['get', 'post', 'put', 'delete']
def get_queryset(self):
return CartItem.objects.filter(cart_id=self.kwargs['cart_pk'])
def get_serializer_class(self):
if self.request.method == 'PUT':
return UpdateCartItemSerializer
elif self.request.method == 'POST':
return CreateCartItemSerializer
else:
return CartItemSerializer
def get_serializer_context(self):
return {
'cart_id': self.kwargs['cart_pk']
}
序列化器.py
class CartItemSerializer(serializers.ModelSerializer):
id = serializers.IntegerField(read_only=True)
student_id = serializers.SerializerMethodField(read_only=True)
def get_student_id(self, cart_item):
return Cart.objects.filter(id=self.context['cart_id'])[0].student_id
class Meta:
model = CartItem
fields = ['id', 'student_id', 'course_id']
class CreateCartItemSerializer(serializers.ModelSerializer):
id = serializers.IntegerField(read_only=True)
def create(self, validated_data):
instance = CartItem.objects.get(cart_id=validated_data['cart_id'],
course_id=validated_data['course_id'])
try:
return instance
except CartItem.DoesNotExist:
instance = CartItem.objects.create(**validated_data)
instance.save()
return instance
class Meta:
model = CartItem
fields = ['id', 'course_id']
class UpdateCartItemSerializer(serializers.ModelSerializer):
def update(self, instance, validated_data):
print(instance.__dict__, validated_data)
current_course_id = instance.course_id
new_course_id = validated_data.get('course_id', instance.course_id)
if current_course_id != new_course_id:
condition = CartItem.objects\
.filter(cart_id=instance.cart_id) \
.filter(course_id=new_course_id) \
.exists()
if not condition:
with transaction.atomic():
CartItem.objects \
.filter(id=instance.id) \
.update(course_id=new_course_id)
old_price = Course.objects \
.filter(id=current_course_id)[0].price
new_price = Course.objects \
.filter(id=new_course_id)[0].price
current_cart_price = Cart.objects \
.filter(id=instance.cart_id)[0].total_price
current_cart_price -= old_price
current_cart_price += new_price
Course.objects \
.filter(id=new_course_id) \
.update(total_price=current_cart_price)
instance.save()
else:
CartItem.objects.filter(id=instance.id).delete()
return Response(status=status.HTTP_204_NO_CONTENT)
return instance
class Meta:
model = CartItem
fields = ['id', 'course_id']
read_only_fields = ('id', )
额外问题: 为什么序列化器的 HTML 表单无法识别我的字段?
我试图评论所有内容以到达错误的位置,但徒劳。
我认为问题就出在这里。如果我快速浏览后正确理解了您的代码,那么您期望此时
Course.objects.filter(id=new_course_id).update(total_price=current_cart_price)
instance.save()
对象
instance
和对象Course.objects.filter(id=new_course_id)
是相同的,并且使用update
后两者具有相同的值。
如果我对你尝试做的事情的理解是正确的,你不应该使用这个逻辑。
update
直接对数据库进行查询,instance
不刷新,并且不调用模型的save
方法。
因此,当您在方法结束时返回
instance
时,您将返回模型的旧版本。
所以,使用类似:
Course.objects.filter(id=new_course_id).update(total_price=current_cart_price)
# instance.save() # not needed
instance.refresh_from_db()
或
# Course.objects.filter(id=new_course_id).update(total_price=current_cart_price)
instance.total_price = current_cart_price
instance.save() # not needed