You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Django REST Framework创建/更新Account模型遇400错误排查

问题排查:DRF创建Account模型时400/500错误

问题描述

尝试通过Django REST Framework指定id和params字段创建或更新Account模型,持续收到400或500错误码,相关代码及日志如下:

客户端代码

data = dict(id=18, params=dict(foo='bar'))
res = requests.post('http://container-django-1:8002/api/account/',
    data=data,
    headers={'Authorization': 'Bearer {0}'.format(instance.bookkeeper.jwt_token)}
)

服务端配置

models.py

class Account(TimestampedModel):
    active = models.BooleanField(null=True, blank=True, default=False)
    params = models.JSONField(default=dict, blank=True)

views.py

class AccountViewSet(viewsets.ModelViewSet):
    serializer_class = AccountSerializer
    queryset = Account.objects.all()
    http_method_names = ['post']

serializer.py

class AccountSerializer(serializers.ModelSerializer):

    class Meta:
        model = Account
        fields = ('id', 'params',)

    def create(self, validated_data):
        return Account.objects.create(id=validated_data['id'],
                                      params=validated_data['params'])

urls.py

router = routers.DefaultRouter()
router.register("account", AccountViewSet, basename="accounts-list")

urlpatterns = [
    path('', include(router.urls)),
]

输出日志

container-django-1  | 2022-09-03T18:14:22.785593661Z Starting development server at http://0.0.0.0:8002/
container-django-1  | 2022-09-03T18:14:22.785604944Z Quit the server with CONTROL-C.
container-django-1  | 2022-09-03T18:17:09.252092179Z Bad Request: /api/account/
container-django-1  | 2022-09-03T18:17:09.253001155Z Bad Request: /api/account/
container-django-1  | 2022-09-03T18:17:09.261351802Z [03/Sep/2022 18:17:09] "POST /api/account/ HTTP/1.1" 400 40

问题原因及解决方案

1. 客户端请求格式错误

当前客户端用data=data发送表单格式数据,但params是嵌套字典的JSON字段,表单格式无法正确解析嵌套结构,导致DRF序列化器验证失败。

解决方法:
将data=data改为json=data,让requests发送JSON格式的请求体:

data = dict(id=18, params=dict(foo='bar'))
res = requests.post('http://container-django-1:8002/api/account/',
    json=data,  # 改为json参数
    headers={'Authorization': 'Bearer {0}'.format(instance.bookkeeper.jwt_token)}
)
# 打印响应详情,定位具体错误
print(res.json())

2. 模型id字段类型不支持手动指定

默认Django模型的id是AutoField(自增主键),数据库会自动生成值,不允许手动插入指定id,这会导致创建时数据库报错(可能触发500,或序列化器验证不通过触发400)。

解决方法:
修改Account模型,将id改为手动可控的主键类型:

class Account(TimestampedModel):
    id = models.IntegerField(primary_key=True)  # 替换默认AutoField
    active = models.BooleanField(null=True, blank=True, default=False)
    params = models.JSONField(default=dict, blank=True)

注意:如果已有数据,需生成并执行数据库迁移,确保字段类型变更兼容现有数据。

3. 序列化器与模型逻辑不匹配

自定义的create方法尝试手动指定id,但如果模型id是AutoField,数据库会拒绝该操作。另外,ModelSerializer默认已支持处理validated_data中的字段,无需手动重写create(除非有额外逻辑)。

优化方案:
移除自定义的create方法,或改为支持“存在则更新,不存在则创建”的逻辑:

class AccountSerializer(serializers.ModelSerializer):
    class Meta:
        model = Account
        fields = ('id', 'params',)

    def create(self, validated_data):
        # 实现创建/更新逻辑
        account, created = Account.objects.update_or_create(
            id=validated_data['id'],
            defaults={'params': validated_data['params']}
        )
        return account

4. 缺少更新接口配置

当前ViewSet只允许post方法(对应创建操作),如果要更新已有Account,需使用put/patch方法访问详情接口(如/api/account/18/),或在create方法中实现上述update_or_create逻辑。


内容的提问来源于stack exchange,提问作者Florent

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 10:06:27