Django REST框架使用AJAX网址指向api详细信息网址

时间:2018-07-12 10:40:38

标签: python ajax django datatables django-rest-framework

我正在使用Django开发数据库程序。该程序从用户的表单/导入的文件中追加数据库,允许按类别列出数据,并按类别进行内联编辑。

我做了很多研究(因为我是django的新人),到目前为止,我已经成功地通过组合其余框架和数据表来生成表格和定制表。

当我尝试对表实施内联编辑时,会出现问题。我使用插件数据表编辑器。我的视图和序列化程序似乎可以正常运行,因为我可以在Api根目录中POSTPUTDELETE。但是然后我无法使ajax url指向方法api详细信息视图,我需要url中的pk为变量才能匹配选择:

我的serializer.py

class TankSerializer(serializers.ModelSerializer):
modified_date = serializers.DateTimeField(format='%d/%m/%Y %H:%M', input_formats=None)
updated_by = serializers.SlugRelatedField(slug_field='last_name', queryset=User.objects.all())
pid = serializers.SlugRelatedField(slug_field='number', queryset=PID.objects.all())
zone = serializers.SlugRelatedField(slug_field='number', queryset=ProcessZone.objects.all())
medium = serializers.SlugRelatedField(slug_field='code', queryset=Medium.objects.all())
revision = serializers.SlugRelatedField(slug_field='code', queryset=Revision.objects.all())
supplier = serializers.SlugRelatedField(slug_field='name', queryset=Supplier.objects.all())
po = serializers.SlugRelatedField(slug_field='number', queryset=PO.objects.all())
material = serializers.SlugRelatedField(slug_field='name', queryset=Material.objects.all())

DT_RowId = serializers.SerializerMethodField()

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

class Meta:
    model = Tank
    fields = (
        'DT_RowId', 'tag', 'description', 'pid', 'zone', 
        'medium', 'revision', 'supplier', 'po', 'material', 
        'volume', 'hight','modified_date','updated_by', 'created_by'
    )

我的views.py

@login_required
@ensure_csrf_cookie
def edit_tanks(request, project_code):
    project = get_object_or_404(Project, code=project_code)
    return render(request, 'edit_tanks.html', {'project': project})

class TankViewSet(viewsets.ModelViewSet):
    queryset = Tank.objects.all().order_by('tag')
    serializer_class = TankSerializer
    lookup_filed = 'pk'

    @action(methods=['get'], detail=True)   
    def get(self, request, pk, project_code, format=None):
        serializer = self.serializer_class(self.queryset, many=True)
        return Response(serializer.data)

    @action(methods=['post'], detail=True)
    def post(self, request, pk=None, format=None):
        serializer = self.serializer_class(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status.HTTP_201_CREATED)
        return Response(serializer.errors, status.HTTP_400_BAD_REQUEST)

    @action(methods=['patch'], detail=True)
    def patch(self, request, pk, format=None):
        queryset = self.get_object(pk)
        serializer = self.serializer_class(queryset, data=request.data, partial=True)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        return Response(serializer.errors, status.HTTP_400_BAD_REQUEST)

    @action(methods=['put'], detail=True)
    def put(self, request, pk, format=None):
        queryset = self.get_object(pk)
        serializer = self.serializer_class(queryset, data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        return Response(serializer.errors, status.HTTP_400_BAD_REQUEST)

    @action(methods=['delete'], detail=True)
    def delete(self, request, pk, format=None):
        queryset = self.get_object(pk)
        queryset.delete()
        return Response(status.HTTP_204_NO_CONTENT)

我的urls.py

router = routers.DefaultRouter()
router.register(r'edit_tanks', views.TankViewSet, 'edit_tanks')

urlpatterns = [
    re_path(r'^projects/(?P<project_code>\d+)/engineering/equipment/edit_tanks/api/', include(router.urls)),
    re_path(r'^projects/(?P<project_code>\d+)/engineering/equipment/edit_tanks/$', views.edit_tanks, name='edit_tanks'),
    path('admin/', admin.site.urls),
]

我的模板edit_tanks.html

{% block content %}
  <div class="row">
    <div class="col-sm-12">
      <table id="edit_tanks" class="stripe row-border order-column" cellspacing="0" style="table-layout: auto; width:100%;">
        <thead>
            <tr>
                <th></th>
                <th>Tag</th>
                <th>Description</th>
                <th>PID</th>
                <th>Zone</th>
                <th>Medium</th>
                <th>Revision</th>
                <th>Supplier</th>
                <th>PO</th>
                <th>Material</th>
                <th>Volume</th>
                <th>Height</th>
                <th>Last updated</th>
                <th>Updated by</th>
            </tr>
        </thead>

      </table>
    </div>
  </div>

{% endblock %}

{% block extra_js %}

<script type="text/javascript">


var editor;

$(document).ready(function() {
    editor = new $.fn.dataTable.Editor( {

        ajax: {
            create: {
                type: 'POST',
                url: 'api/edit_tanks/?format=datatables',
            },
            edit: {
                type: 'PUT',
                url: 'api/edit_tanks/{{tank_pk}}/',
            },
            remove: {
                type: 'DELETE',
                url: 'api/edit_tanks/{{tank_pk}}/',
            }
        },

        table: "#edit_tanks",
        fields: [ {
                label: "Tag:",
                name: "tag"
            }, {
                label: "Description:",
                name: "description"
            }, {
                label: "Ravision:",
                name: "revision.code",
                type: "select"
            }, {
                label: "PO:",
                name: "po.number",
                type: "select"
            },
        ]
    } );    

    // Activate an inline edit on click of a table cell
    $('#edit_tanks').on( 'click', 'tbody td:not(:first-child)', function (e) {
        editor.inline( this );
    } );

    var table = $('#edit_tanks').DataTable({
        "processing": true,
        "serverSide": true,
        ajax: {
            url: "api/edit_tanks/?format=datatables",
            data: { 
            csrfmiddlewaretoken: "{{ csrf_token }}"
            }
        },
        dom: 'Bfrtip',
        language: {
            search: "_INPUT_",
            searchPlaceholder: "Search..."
        },

        "columns": [
            {
                data: null,
                defaultContent: '',
                className: 'select-checkbox',
                orderable: false
            },
            {"data": "tag"},
            {"data": "description"},
            {"data": "pid", "number": "pid.number"},
            {"data": "zone", "number": "zone.number"},
            {"data": "medium", "code": "medium.code"},
            {"data": "revision", "code": "revision.code"},
            {"data": "supplier", "name": "supplier.name"},
            {"data": "po", "number": "po.number"},
            {"data": "material", "name": "material.name"},
            {"data": "volume"},
            {"data": "hight"},
            {"data": "modified_date"},
            {"data": "updated_by", "last_name": "user.last_name"},
        ],
        autoFill: {
            columns: ':not(:first-child)',
            editor:  editor
        },
        keys: {
            columns: ':not(:first-child)',
            editor:  editor
        },
        select: {
            style:    'os',
            selector: 'td:first-child',
            blurable: true
        },
        buttons: [ 
            { extend: "create", editor: editor},
            { extend: "edit",   editor: editor },
            {
                extend: "selected",
                text: 'Duplicate',
                action: function ( e, dt, node, config ) {
                    // Start in edit mode, and then change to create
                    editor
                        .edit( table.rows( {selected: true} ).indexes(), {
                            title: 'Duplicate record',
                            buttons: 'Create from existing'
                        } )
                        .mode( 'create' );
                }
            },
            { extend: "remove", editor: editor }
            ]
    });

});

</script>
{% endblock %}

当我尝试编辑或内联编辑时,我得到了

  

错误404 JSON:{“ detail”:“未找到。”}

当我用特定数字替换ajax网址中的pk时,我得到

  

错误400

和JSON抱怨所有字段都不是必填字段!

这时我已经被卡住了一段时间,但找不到解决我问题的答案...。我们将不胜感激!

1 个答案:

答案 0 :(得分:1)

这可能会帮助某人。...

在数据表中,当在客户端上处理CRUD方法并使用Django Rest Framwork api时,我们需要将正确的方法指向正确的url,这意味着:

  • POSTGET的列表中使用“列表URL”(因为我们没有处理单个现有实例),因此在我的情况下,URL为url: 'api/edit_tanks/'
  • 使用AJAX {{1}中的PUTDELETEGET实例的用户(需要传递pk来标识实例)的“详细网址” }}可用于获取网址中的_id_。所以我的网址是:pk

这应该解决错误:

  

{“详细信息”:“未找到。”}

对于“必填字段”错误,请确保在序列化程序url: 'api/edit_tanks/_id_'中指定所有不需要的字段。我亲自在所有字段中指定了它,然后让模型处理需求。

关于视图(API视图):

required=False已经包含所有CRUD方法,可以随时重写以添加新参数或拥有自己的特定逻辑。我的看法变成:

ModelViewSet