DRF中通过Project关联查询Profile触发ValueError问题求助
问题原因及解决方案
错误根源
你遇到的ValueError: Cannot query 'Shahryar Bin Talib': Must be 'Project' instance.错误,核心原因是Project模型中外键User的related_name设置为单数project,与一对多的关联关系不匹配,导致序列化时DRF对反向关联的处理出现混淆:
- Project与User是一对多关系(一个User可拥有多个Project),但你将
related_name设为单数project,Django会默认认为user.project是单个Project实例,而非多个实例的查询管理器。 - 在ProfileSerializer中,你尝试用
ProjectSerializer(source='user.project', many=True)序列化该用户的所有项目,DRF在解析user.project时,无法正确识别这是一个多实例的查询管理器,进而在内部处理时将User实例(或其用户名)错误地当作Project实例进行查询,触发该错误。
解决方案
有两种修复方式,任选其一即可:
方式一:修正related_name为复数
修改models.py中Project模型的User外键related_name为复数形式(符合一对多关系的语义):
class Project(TimeStampedModel): """ A model representing a project """ user = models.ForeignKey( User, on_delete=models.CASCADE, blank=True, related_name='projects', # 改为复数projects help_text='The user that created the project.' ) # 其他字段保持不变
同时更新serializers.py中ProfileSerializer的project字段source:
class ProfileSerializer(serializers.ModelSerializer): user = serializers.ReadOnlyField(source='user.username') skills = serializers.StringRelatedField(many=True) project = ProjectSerializer(source='user.projects', many=True) # 改为user.projects class Meta: model = Profile exclude = ['bio']
方式二:在Serializer中明确调用管理器的all()方法
如果不想修改related_name,可在ProfileSerializer的project字段source中指定调用管理器的all()方法来获取正确的QuerySet:
class ProfileSerializer(serializers.ModelSerializer): user = serializers.ReadOnlyField(source='user.username') skills = serializers.StringRelatedField(many=True) project = ProjectSerializer(source='user.project.all', many=True) # 添加.all class Meta: model = Profile exclude = ['bio']
为什么另一个视图能正常工作?
你提到的ProfileViewSet中的profile_projects接口直接通过Project.objects.filter(user_id=pk)查询项目,这个查询是直接基于User的id进行过滤,没有用到反向关联的related_name,因此不会触发上述语义混淆的问题。
内容的提问来源于stack exchange,提问作者apeCode
相关产品推荐
相关产品推荐

