Django序列化器设置IntegerField报错:'int'对象无'pk'属性
问题排查与解决思路
这个错误的根源在于嵌套序列化器处理外键字段时的类型不匹配,我们一步步拆解:
为什么会报错?
看你的栈追踪,错误来自rest_framework/relations.py里的to_representation方法,它尝试调用value.pk但传入的是整数。这是因为:
- 你的
MarketActionClearingSerializer是ModelSerializer,而MarketAction模型里的marketSessionid、marketActorid等字段应该是外键(ForeignKey),所以ModelSerializer默认会把这些字段处理成PrimaryKeyRelatedField。 - 你先通过
MarketActionSerializer(ma).data得到了序列化后的字典,里面的外键字段是整数ID;接着把这个字典传给PrioritisedMarketActionSerializer的marketaction字段。 - 当
PrioritisedMarketActionSerializer序列化这个字典时,嵌套的MarketActionSerializer会对每个字段执行to_representation——对于PrimaryKeyRelatedField类型的字段,它期望接收的是模型实例,而不是整数ID,所以尝试访问整数的pk属性时就抛出了错误。
解决方法(按推荐程度排序)
方法1:直接传入模型实例(最简单)
不需要先序列化ma成字典,直接把MarketAction的模型实例传给prioritised_ma的marketaction字段:
# 替换你原来的逻辑 prioritised_ma = { "marketaction": ma, # 直接传模型实例,不是序列化后的data "priority": 1 } output.append(PrioritisedMarketActionSerializer(prioritised_ma).data)
这样嵌套的MarketActionSerializer会自动处理模型实例,正确序列化所有字段,包括外键对应的ID。
方法2:显式声明外键字段为IntegerField
如果你必须用字典传递数据,可以修改MarketActionClearingSerializer,把所有外键字段显式声明为IntegerField,覆盖ModelSerializer的默认行为:
class MarketActionClearingSerializer(serializers.ModelSerializer): id = serializers.IntegerField(required=True) # 显式声明外键字段为IntegerField marketSessionid = serializers.IntegerField() marketActorid = serializers.IntegerField() formid = serializers.IntegerField() actionTypeid = serializers.IntegerField() statusid = serializers.IntegerField() loadid = serializers.IntegerField() class Meta: model = MarketAction fields = ( 'id', 'date', 'actionStartTime', 'actionEndTime', 'value', 'uom', 'price', 'deliveryPoint', 'marketSessionid', 'marketActorid', 'formid', 'actionTypeid', 'statusid', 'loadid', 'cpu', 'ram', 'disk',) depth = 0 # 保留你的error_status_codes
这样序列化器会把这些字段当成普通整数处理,不会尝试访问pk属性。
方法3:使用普通Serializer替代ModelSerializer(适合不需要模型绑定的场景)
如果MarketActionSerializer不需要和模型强绑定,可以改成普通的serializers.Serializer,手动声明所有字段:
class MarketActionSerializer(serializers.Serializer): id = serializers.IntegerField(required=True) date = serializers.DateTimeField() actionStartTime = serializers.DateTimeField() actionEndTime = serializers.DateTimeField() value = serializers.DecimalField(max_digits=10, decimal_places=2) # 按你的模型字段类型调整 uom = serializers.CharField() price = serializers.DecimalField(max_digits=10, decimal_places=2) deliveryPoint = serializers.CharField() marketSessionid = serializers.IntegerField() marketActorid = serializers.IntegerField() formid = serializers.IntegerField() actionTypeid = serializers.IntegerField() statusid = serializers.IntegerField() loadid = serializers.IntegerField() cpu = serializers.IntegerField() ram = serializers.IntegerField() disk = serializers.IntegerField()
然后在PrioritisedMarketActionSerializer里使用这个普通Serializer,就不会有外键字段的自动转换问题了。
另外注意你代码里的小笔误:PrioritisedMarketActionsSerializer应该是PrioritisedMarketActionSerializer(多了个s),如果是复制粘贴错误的话记得修正。
内容的提问来源于stack exchange,提问作者Lazar Vlad
相关产品推荐
相关产品推荐

