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

Django REST API集成DataTables Editor创建功能报400错误求助

Django REST API集成DataTables Editor创建请求400错误排查

问题描述

在Django REST API中集成DataTables Editor时,数据表格可正常显示,但点击创建按钮返回"POST /dashboard/api/investigator/ HTTP/1.1" 400 160错误。400状态码表示请求无效,需排查错误原因,同时说明返回信息中160的含义。

相关代码与请求信息

urls.py

from django.urls import path, include
from . import views

from rest_framework import routers
from .views import StudyList, StudyDetail, InvestigatorView

app_name = 'dashboard'
router = routers.DefaultRouter()
router.register('study', views.StudyView)
router.register('investigator', views.InvestigatorView)
router.register('lead', views.LeadView)
router.register('institution', views.InstitutionView)
router.register('site', views.SiteView)

investigator_list = InvestigatorView.as_view({
    'get': 'list',
    'post': 'create'
})
investigator_detail = InvestigatorView.as_view({
    'get': 'retrieve',
    'PUT': 'update',
    'patch': 'partial_update',
    'delete': 'destroy'
})

urlpatterns = [
    path('', views.datatables, name='datatable'),
    path('investigator/', views.datatables_investigator, name='datatables_investigator'),
    path('api/', include(router.urls)),
    path('api/investigator/', investigator_list, name='InvestigatorList'),
    path('api/investigator/<int:pk>', investigator_detail, name='InvestigatorDetail'),
    path('api/study/', StudyList.as_view(), name='StudyList'),
    path('api/study/<int:pk>/', StudyDetail.as_view(), name='StudyDetail')
]

datatables_investigator.html

{% extends 'base_datatables_editor.html' %}

{% block content %}
<h1 style="text-align: center; padding-top: 1em; padding-bottom: 1em;">Investigators</h1>
<div class="row">
    <div class="col-sm-12">
        <table id="InvestigatorDataTable" class="table table-striped table-bordered" style="width:100%">
            <thead>
                <tr>
                    <th scope="col">First Name</th>
                    <th scope="col">Last Name</th>
                    <th scope="col">Name</th>
                    <th scope="col">Email</th>
                    <th scope="col">Institution</th>
                </tr>
            </thead>
        </table>
    </div>
</div>
{% endblock content %}

{% block extra_js %}
    <script>
        var editor; 

        $(document).ready(function() {
            editor = new $.fn.dataTable.Editor( {
                ajax: {
                    create: {
                    type: "POST",
                    url:  'http://127.0.0.1:8000/dashboard/api/investigator/'
                    contentType: 'application/json', 
                    data: function ( d ) {
                        return JSON.stringify( d );
                    },
                    edit: {
                    type: "PUT",
                    url:  "http://127.0.0.1:8000/dashboard/api/investigator/_id_"
                    },
                    remove: {
                    type: "DELETE",
                    url:  "http://127.0.0.1:8000/dashboard/api/investigator/_id_"
                    }},
                table: '#InvestigatorDataTable',
                data: "symbol",
                defaultContent: "",
                contentType: 'application/json',
                csrfmiddlewaretoken: window.CSRF_TOKEN,
                table: '#InvestigatorDataTable',
                idSrc: "id",
                dataSrc: "data",
                fields: [ {
                    label: "ID:",
                    name: "id"
                }, {
                    label: "Last Name:",
                    name: "last_name"
                }, {
                    label: "First Name:",
                    name: "first_name"
                }, {
                    label: "Email:",
                    name: "email"
                }, {
                    label: "Institution:",
                    name: "institution",
                    ///type: "select",
                    ///placeholder: "Select an institution"
                }, {
                    label: "Created At:",
                    name: "created_at",
                    type: "datetime",
                    def:    function () { return new Date(); },
                    displayFormat: 'YYYY-MM-DD HH:mm:ss.SSSS'
                    ///2022-05-19T17:59:46.167754Z
                }] 
            });
            $('#InvestigatorDataTable').DataTable({
                serverSide: true,
                ajax: 'http://127.0.0.1:8000/dashboard/api/investigator/?format=datatables',
                dom: 'Bfrtrip',
                columns: [
                    {data: "last_name", },
                    {data: "first_name",},
                    {data: null, render: function ( data, type, row ) {
                        return data.first_name + " " + data.last_name
                    }},
                    {data: "email", orderable: false},
                    {data: "institution.name", name: "institution.name", orderable: true},
                    ],
                columnDefs: [
                    { targets: [2, 3, 4,], visible: true},
                    { targets: '_all', visible: false }
                ],
                select: true,
                buttons: [
                    { extend: "create", editor: editor },
                    { extend: "edit", editor: editor }, 
                    { extend: "remove", editor: editor }
                ]
            });
        });
    </script>
{% endblock %}

serializers.py

from rest_framework import serializers
from dashboard.models import Study, Investigator, Lead, Institution, Site

class InstitutionSerializer(serializers.ModelSerializer):
    class Meta:
        model = Institution
        fields = ('name', 'dept')

class InvestigatorSerializer(WritableNestedModelSerializer, serializers.ModelSerializer):
    institution = InstitutionSerializer
    class Meta:
        model = Investigator
        fields = ('__all__')
        depth = 1
        datatables_always_serialize = ('id',)

views.py

from django.shortcuts import render, redirect
from .models import Study, Investigator, Lead, Institution, Site
from .forms import StudyForm
from django.views.decorators.csrf import csrf_exempt

from rest_framework import viewsets, generics
from rest_framework.permissions import AllowAny
from .serializers import StudySerializer, InvestigatorSerializer, LeadSerializer, InstitutionSerializer, SiteSerializer

# Datatable Views

@csrf_exempt#@csrf_protect#@ensure_csrf_cookie
def datatables(request):
    return render(request, 'datatables.html')

def datatables_investigator(request):
    return render(request, 'datatables_investigator.html')

#API Views

class InvestigatorView(viewsets.ModelViewSet):
    queryset = Investigator.objects.all()
    serializer_class = InvestigatorSerializer
    permission_classes = [AllowAny]

class InstitutionView(viewsets.ModelViewSet):
    queryset = Institution.objects.all()
    serializer_class = InstitutionSerializer

models.py

class Investigator(models.Model):
    id = models.AutoField(unique=True, primary_key=True)
    last_name = models.CharField(max_length=50)
    first_name = models.CharField(max_length=50)
    email = models.CharField(max_length=50)
    created_at = models.DateTimeField(auto_now_add=True)
    institution = models.ForeignKey('Institution', models.DO_NOTHING, )

    class Meta:
        managed = True
        db_table = 'investigator'
    def __str__(self):
        return str(self.last_name)

发送的请求内容

{"data":{"0":{"last_name":"test2","first_name":"test2","email":"test2","institution":"1"}},"action":"create"}


问题解析与修复方案

关于返回信息中的160

160是响应内容的字节大小,不是错误码,仅表示后端返回的错误提示内容长度,无需关注这个数字,重点排查400状态码对应的具体请求无效原因。

核心错误点与修复

  1. Serializer嵌套配置错误
    InvestigatorSerializer中institution = InstitutionSerializer缺少括号,应为institution = InstitutionSerializer();且当前配置为嵌套序列化,后端会期望接收Institution的完整字段(name、dept),但前端仅传递了机构ID,导致序列化失败。
    修复方案:区分读写逻辑,查询时返回嵌套数据,创建/更新时接收机构ID:

    class InvestigatorSerializer(serializers.ModelSerializer):
        class Meta:
            model = Investigator
            fields = '__all__'
            datatables_always_serialize = ('id',)
    
        def to_representation(self, instance):
            # 查询时返回嵌套机构信息
            representation = super().to_representation(instance)
            representation['institution'] = InstitutionSerializer(instance.institution).data
            return representation
    
  2. DataTables Editor请求格式与Django REST不兼容
    DataTables Editor默认发送的请求包含外层data和action结构,但Django REST ModelViewSet期望直接接收模型字段的JSON对象。
    修复方案:前端调整请求数据格式:

    create: {
        type: "POST",
        url: '/dashboard/api/investigator/',
        headers: {
            'X-CSRFToken': window.CSRF_TOKEN
        },
        contentType: 'application/json',
        data: function (d) {
            // 提取有效数据并转换机构ID为数字
            let payload = Object.values(d.data)[0];
            payload.institution = parseInt(payload.institution);
            return JSON.stringify(payload);
        },
        success: function(json) {
            // 适配Editor的返回格式要求
            return { data: [json] };
        }
    }
    
  3. URL路由冲突
    同时注册了router的investigator路由和手动定义的investigator_list,导致路由匹配混乱。ModelViewSet已包含所有CRUD动作,无需重复定义。
    修复方案:删除手动定义的investigator_list和investigator_detail,保留router路由:

    urlpatterns = [
        path('', views.datatables, name='datatable'),
        path('investigator/', views.datatables_investigator, name='datatables_investigator'),
        path('api/', include(router.urls)),
        path('api/study/', StudyList.as_view(), name='StudyList'),
        path('api/study/<int:pk>/', StudyDetail.as_view(), name='StudyDetail')
    ]
    
  4. 不必要字段提交
    前端提交了id和created_at字段,但id为AutoField由后端自动生成,created_at为auto_now_add=True无需前端传递,会导致序列化错误。
    修复方案:在Editor的fields配置中移除这两个字段。

  5. CSRF令牌处理错误
    前端未将CSRF令牌放入请求头,Django默认会校验CSRF令牌导致请求被拒绝。
    修复方案:在ajax请求中添加X-CSRFToken请求头(如上述前端代码示例)。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 11:31:01