Django Query如何使用_set过滤条件校验关联外键所属关系?
问题原因
你原来的校验逻辑存在两个核心错误:
- 关联字段遍历路径错误:
replied_by是HotelUser类型的对象,本身没有reservation属性,你需要从Reply关联的Review出发,逐层向上找到对应的酒店,正确路径为self.reply_to.reservation.room.hotel - 校验逻辑错误:
filter()返回的是查询集,直接和用户对象比较永远不会成立,应该用exists()判断该酒店的员工列表中是否存在对应用户
可行解决方案
第一步:修正Reply模型的clean方法
把你原来的clean方法替换为以下实现:
from django.core.exceptions import ValidationError class Reply(BaseModel): reply_to = models.OneToOneField( Review, on_delete=models.CASCADE, error_messages={'unique': 'Reply to this review already exists.'}) replied_by = models.ForeignKey(HotelUser, on_delete=models.CASCADE) def clean(self): # 获取回复对应的酒店 target_hotel = self.reply_to.reservation.room.hotel # 校验当前回复人是否是该酒店的员工 is_hotel_staff = target_hotel.staff_set.filter(user=self.replied_by).exists() if not is_hotel_staff: raise ValidationError("仅对应酒店的员工可以回复该评价")
第二步:确保clean方法被触发
Django的clean方法不会在调用save()时自动执行,你需要根据使用场景主动触发校验:
- 如果你在Admin后台操作,Django会自动调用
full_clean()触发校验,不需要额外处理 - 如果你在自定义逻辑/接口中保存Reply对象,保存前需要手动调用校验:
reply = Reply(...) reply.full_clean() # 触发clean方法执行校验 reply.save()
如果你使用Django REST Framework开发接口,也可以把校验逻辑放到序列化器的validate方法中,效果一致:
from rest_framework import serializers class ReplySerializer(serializers.ModelSerializer): class Meta: model = Reply fields = "__all__" def validate(self, attrs): target_hotel = attrs['reply_to'].reservation.room.hotel is_hotel_staff = target_hotel.staff_set.filter(user=attrs['replied_by']).exists() if not is_hotel_staff: raise serializers.ValidationError("仅对应酒店的员工可以回复该评价") return attrs
内容的提问来源于stack exchange,提问作者lord stock
相关产品推荐
相关产品推荐

