Django DRF提交Residence数据报错:got an unexpected keyword argument 'hotel_id'
Django外键关联POST提交报错解决方案
报错根因
出现这个报错有两个核心问题:
- 外键字段命名不符合Django ORM规范:你给外键字段命名为
hotel_id,Django处理外键时会自动给存储主键的数据库列追加_id后缀,最终对应数据库字段变为hotel_id_id,直接传递hotel_id参数创建Residence实例时,ORM无法匹配到正确的字段赋值逻辑,尤其你嵌套了Hotel序列化器后,hotel_id对应的是酒店字典数据,不是合法的Hotel实例。 - 嵌套序列化的创建逻辑未处理关联数据:你直接将包含嵌套酒店字典的
validated_data传给Residence.objects.create(),没有提前将酒店数据转为对应的Hotel实例。
修复步骤
第一步:调整模型外键命名(必改,避免后续字段映射混乱)
修改Residence模型的外键字段命名为常规的hotel,同时调整related_name为反向查询更合理的命名,另外补上所有CharField必填的max_length参数:
class Hotel(models.Model): name = models.CharField(max_length=100) country = models.CharField(max_length=100) city = models.CharField(max_length=100) street = models.CharField(max_length=200) class Residence(models.Model): # 把原hotel_id改为hotel,符合ORM命名规范 hotel = models.ForeignKey(Hotel, on_delete=models.DO_NOTHING, related_name='residences') house_number = models.CharField(max_length=50)
第二步:根据业务场景调整序列化器
场景1:提交Residence时同时创建关联的新Hotel
修改ResidenceSerializer的create方法,先提取酒店数据创建Hotel实例,再用该实例创建Residence:
class HotelSerializer(serializers.HyperlinkedModelSerializer): class Meta: model = Hotel fields = ['name', 'country', 'city', 'street'] class ResidenceSerializer(serializers.HyperlinkedModelSerializer): hotel = HotelSerializer() class Meta: model = Residence fields = ['house_number', 'hotel'] def create(self, validated_data): # 先取出嵌套的酒店数据 hotel_data = validated_data.pop('hotel') # 创建酒店实例 hotel = Hotel.objects.create(**hotel_data) # 把酒店实例传入创建Residence return Residence.objects.create(hotel=hotel, **validated_data)
场景2:提交Residence时仅关联已有的Hotel,无需新增酒店
不需要可写的嵌套HotelSerializer,直接用主键关联即可,如果需要返回接口时带酒店详情,可以把HotelSerializer设为只读,额外加可写的酒店id字段:
class ResidenceSerializer(serializers.HyperlinkedModelSerializer): # 只读,返回时展示酒店详情 hotel = HotelSerializer(read_only=True) # 可写,提交时传已有的酒店id hotel_id = serializers.PrimaryKeyRelatedField( queryset=Hotel.objects.all(), source='hotel', write_only=True ) class Meta: model = Residence fields = ['house_number', 'hotel', 'hotel_id']
这种场景下POST提交时只需要传house_number和hotel_id两个字段即可,无需传整个酒店的详细信息。
第三步:迁移模型生效修改
修改完模型后执行以下命令更新数据库结构:
python manage.py makemigrations python manage.py migrate
调整完之后再次调用POST接口即可正常提交数据。
内容的提问来源于stack exchange,提问作者user13066942
相关产品推荐
相关产品推荐

