【问题标题】:POST with Django Rest Framework and DataTables returns a 400 bad request使用 Django Rest Framework 和 DataTables 的 POST 返回 400 错误请求
【发布时间】:2026-01-19 00:30:01
【问题描述】:

当我使用 DRF 的可浏览 API 时,我可以 POST 和 DELETE。尝试通过我的 tradingbook.html(w/DataTables)复制此内容(新/编辑/删除):错误请求:/api/trading/ 带有“POST /api/trading/?format=datatables&keep=id HTTP/1.1” 400 274. 网络检查器提供 {"data": { "trader": [ "This field is required."这适用于每个领域。 Django 版本 3.0.4、DRF 3.11、Python3.7.6 数据表编辑器和 DRF 数据表编辑器。

我花了这么多时间在这件事上,我永远不会承认。

class TradingBook(models.Model):
trader =        models.TextField(max_length=10)
status =        models.TextField(max_length=10)
price =         models.TextField(max_length=10)
volume =        models.TextField(max_length=10)
index =         models.TextField(max_length=10)
cpty =          models.TextField(max_length=10)

class Meta:
        ordering = ['trader']

def __str__(self):
    return self.trader

序列化器.py

class TradingBookSerializer(serializers.ModelSerializer):
id = serializers.IntegerField(read_only=True)

class Meta:
    model = TradingBook
    fields = "__all__" 

DT_RowId = serializers.SerializerMethodField() 

def get_DT_RowId(self, TradingBook):
    return 'row_%d' % TradingBook.pk

views.py

@csrf_exempt#@csrf_protect#@ensure_csrf_cookie
def tradingsomething(request):  
    return render(request, 'trading/tradingbook.html')

@method_decorator(login_required, name="dispatch")
class TradingBookViewSet(viewsets.ModelViewSet):
        queryset = TradingBook.objects.all()#.order_by('trader')
        permission_classes  = [permissions.AllowAny]   
        serializer_class = TradingBookSerializer

urls.py

path('trading', trading_views.tradingsomething),
    path('trading/<int:pk>/', trading_views.TradingBookViewSet, name='TradingBook'),

    path('api/', include(router.urls)),

urlpatterns += router.urls

还有我的tradingbook.html

<script>
$(document).ready(function() {

    function csrfSafeMethod(method) {
    // these HTTP methods do not require CSRF protection
    return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
    }
    $.ajaxSetup({
    beforeSend: function(xhr, settings) {
        if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
            xhr.setRequestHeader("X-CSRFToken", csrftoken);
        }
    }
    });
    var csrftoken =  jQuery("[name=csrfmiddlewaretoken]").val(); // <--important
    
    
    editor = new $.fn.dataTable.Editor( {
        ajax:"/api/trading/?format=datatables&keep=id",
        table: "#TradingBook",
        fields: [ 
            {   label:  "trader:",
                name:   "trader"
             },
            {   label:  "status:",
                name:   "status"
             }, 
            {   label:  "price:",
                name:   "price"
             }, 
            {   label:  "volume:",
                name:   "volume",
             },
            {   label:  "index:",
                name:   "index",
             },
            {   label:  "cpty:",
                name:   "cpty",
             },
        ]
     } );    
    $('#TradingBook').on( 'click', 'tbody td:not(:first-child)', function (e) {
        editor.inline( this );
     } );

    var table = $('#TradingBook').DataTable({
        ajax:"/api/trading/?format=datatables&keep=id",
        dom: 'Bfrtip',
        headers: {'X-CSRFToken': '{{ csrftoken }}'},
        processing: true,
        serverSide: true,
        select: true, 
        type: "POST",  
        language: {
            search: "_INPUT_",
            searchPlaceholder: "Search..."
         },
        columns: [
            {"data": "trader"},
            {"data": "status"},
            {"data": "price"},
            {"data": "volume"},
            {"data": "index"},
            {"data": "cpty"},
         ],
        select: true,
        buttons: [
            {extend: "create", editor: editor},
            {extend: "edit", editor: editor},
            {extend: "remove", editor: editor}     
         ],
     });
    table.buttons().container()
        .appendTo($('.col-md-6:eq(0)', table.table().container()));

 });

</script>
{% block content %} 
  {% csrf_token %}
 <div class="container" style="font-size: .9em;">
        <div class="row">
            <div class="col-sm-12">
                <table id="TradingBook" class="table table-striped table-bordered" style="width:100%">
                    <thead>
                    
                    <tr>
                    <th data-data="trader">trader</th>
                    <th data-data="status">status:</th>
                    <th data-data="price">price:</th>
                    <th data-data="volume">volume:</th>
                    <th data-data="index">index</th>
                    <th data-data="cpty">Cprty:</th>
                    </tr>
                    </thead>
                </table>
            </div>
        </div>
    </div>
{% endblock %}

my web inspector

this is what happens when I try to edit from http://127.0.0.1:8000/trading 和终端返回 错误请求:/api/trading/ [15/May/2020 14:06:06] “POST /api/trading/?format=datatables&keep=id HTTP/1.1”400 274

这是我第一次敢问问题,希望描述得透彻。我担心这对回答的人来说可能是微不足道的,但我非常感谢您抽出宝贵的时间。

【问题讨论】:

    标签: django datatables


    【解决方案1】:

    现在可以通过 DataTables JS 插入来删除

    remove: {
                type: 'DELETE',
                headers: { "X-CSRFTOKEN": csrftoken },
                url:        "/api/trading/_id_/",
                contentType: 'application/json',
                data: function ( d ) {
                    return JSON.stringify( d );
                },
            },

    但是创建和编辑仍然返回 400 BAD 请求。感谢SO帖子 我现在可以在我的错误请求上显示 ID 号。正在进行中。

     edit: {
            type:       'POST',
            headers:     {'X-CSRFToken': 'csrftoken'},
            url:        "/api/trading/_id_/",
            contentType:'application/json'},
    

    返回 错误请求:/api/trading/6/ -> "POST /api/trading/6/ HTTP/1.1" 400 73

    【讨论】:

    • @jimMouette...我目前正在处理同样的问题,在我的搜索中,我遇到了你的帖子。您最终是否找到了解决错误请求的方法?删除甚至在这里都不起作用。
    【解决方案2】:

    我遇到了同样的问题,我的问题是我在 DataTables 声明中的字段名称之一与我的模型不匹配。只是一个愚蠢的错误。

    【讨论】: