有两个提交的 Django 表单,不会响应我创建的文件

Django form with two submits, won't respond with the file I create

编辑:我在尝试单击“导出到 KML”按钮时在 Web 控制台中看到的错误:

VM211:1 Uncaught SyntaxError: Unexpected token < in JSON at position 0
    at JSON.parse (<anonymous>)
    at Object.success ((index):260)
    at j (jquery.min.js:2)
    at Object.fireWith [as resolveWith] (jquery.min.js:2)
    at x (jquery.min.js:5)
    at XMLHttpRequest.b (jquery.min.js:5)

javascript:

 $('form').submit(function(e){
            $.post('/swsite/globe/', $(this).serialize(), function(data){ 

                //this 

                var json = JSON.parse(data);

                var jsonf = JSON.parse(json.data);
                var json2 = JSON.parse('{"foo" : "bar"}')

                console.log(JSON.parse(data).data);
                for(var i=0; i<jsonf.features.length; i++)
                {
                    var entitycesium = new Cesium.Entity();
                    entitycesium.name = jsonf.features[i].properties.name;
                    entitycesium.polygon=new Cesium.PolygonGraphics({
                                hierarchy :  Cesium.Cartesian3.fromDegreesArray([
                                        jsonf.features[i].geometry.coordinates[0][0][0],jsonf.features[i].geometry.coordinates[0][0][1],
                                        jsonf.features[i].geometry.coordinates[0][1][0],jsonf.features[i].geometry.coordinates[0][1][1],
                                        jsonf.features[i].geometry.coordinates[0][2][0],jsonf.features[i].geometry.coordinates[0][2][1],
                                        jsonf.features[i].geometry.coordinates[0][3][0],jsonf.features[i].geometry.coordinates[0][3][1],
                                        jsonf.features[i].geometry.coordinates[0][4][0],jsonf.features[i].geometry.coordinates[0][4][1],
                                    ]),
                                outline:true,
                                outLineColor :  Cesium.Color.RED,
                                material : Cesium.Color.GREEN.withAlpha(0.1),
                            });


                    //when sar processor builds out the json add in the deepviewerurl into it too and ready for loading into db.
                    //entitycesium.description= '<a href=\"' + jsonf.features[i].properties.file_name + '\" target="_blank">Full Resolution Viewer</a>';

                    entitycesium.description= '<a href=\"' +  jsonf.features[i].properties.dzi_location + ' \" target="_blank">Full Resolution Viewer</a>' + 
                        '<p> Country code ' + jsonf.features[i].properties.country_code + '</p>' +
                        '<p> Corner coords ' + jsonf.features[i].properties.corner_coords + '</p>' +
                        '<p> Sensor: ' + jsonf.features[i].properties.sensor + '</p>' +
                        '<p> Target: ' + jsonf.features[i].properties.targetName + '</p>' +
                        '<p> Collection Date: ' + jsonf.features[i].properties.collection_date + '</p>';


                    viewer.entities.add(entitycesium);


                    var numpoints=5;
                    for(var np =0; np<numpoints; np++)
                    {

                //        console.log(jsonf.features[i].geometry.coordinates[0][np]);

                    }
                  //  console.log("BREAK");

                }
                //I really hate how the getById does nothing
                    var ev= viewer.entities;
                    viewer.flyTo(ev);
                    //jsonf.features[currentFeature].geometry.coordinates[0][0-5][0-2]
                    //console.log(jsonf.features[0].geometry.coordinates);
                    for(var i=0; i<ev.values.length; i++)
                    {

                        $('#entitylist').append('<option value ='+ ev.values[i].id +'> '+  ev.values[i].name + '</option>');

                    }
                //$('.message').html(ev.values[0].id);
                    //$('.message').html(json.data);
            });
            e.preventDefault();
        });

我不关心的是为什么浏览器会关心返回的是文件吗?

所以我终于让两个提交按钮工作了,然后我想我可以复制正确的代码并将其放在操作的正确部分。我的 views.py 这个动作看起来像:

def globe(request):

    if request.method == 'POST':
        form = EntityGlobeForm(request.POST)

        #two submit butotns
        #hidden_checkbox means they are interacting with the form
        if request.POST.get('hidden_checkbox'):

            #put items on the virtual globe
            if form.is_valid():
                #you are going to have to make a panel and paginate footprints 


                #object_list = ChangeDetectCSV.objects.filter(processing_level='RAW') #AND DATE

                sensor = form.cleaned_data.get('layer') #it is really sensor
                #if sensor is not 
                object_list = CesiumEntity.objects.filter(sensor = sensor)
                jdata= serialize('geojson', object_list,
                    geometry_field='mpoly',
                    fields=('name','file_name', 'id', 'dzi_location', 'country_code', 'corner_coords', 'sensor', 'targetName', 'collection_date'))

            return HttpResponse(json.dumps({'data': jdata}))
        #the other means they clicked the download option instead
        else:
                # Create the HttpResponse object with the appropriate KML.
            print 'building kml'
            kml = simplekml.Kml()
            kml.newpoint(name="Kirstenbosch", coords=[(18.432314,-33.988862)])  # lon, lat, optional height
            response = HttpResponse(kml.kml())
            response['Content-Disposition'] = 'attachment; filename="botanicalgarden.kml"'
            response['Content-Type'] = 'application/kml'
            print 'about to return response: ' + str(response)
            return response

    else:
        form = EntityGlobeForm

    return render_to_response('swsite/sw_nga_globe.html', {'form':form },
        context_instance=RequestContext(request))

我在黑客攻击方面确实得到了一些帮助POST.get(模板代码在这里)

 <form action="/" method="post" id="form">{% csrf_token %}
               <!--  {{ form.as_table     }} -->
                <table>
                    {% for field in form %}
                    <tr><td><font color="white">{{field}}</font></td></tr>
                    {% endfor %}
                </table>
                <!-- input type="submit" name="LoadLayer" value="Load Entities" />
                <input type="submit" name="notloadlayer" value="Export KML" / -->
                <input type="checkbox" name="hidden_checkbox" id="hidden_checkbox" style="display:none"/>
                <input type="button" value="Load Entities" data-action="true"/>
                <input type="button" value="Export KML" data-action="false"/>                
            </form>

所以打印响应是 KML 文件,但它永远不会返回到浏览器,没有任何反应。我认为设置类型和配置会告诉浏览器正确的事情。我有通过 link 在它自己的操作中构建 KMl 的代码,它工作正常,现在将它填充到下面的其他操作代码中 (globe) 现在不起作用了吗?浏览器什么都不做,文件永远不会弹出下载甚至启动 google earth 就像它那样(因为它是一个 KML 文件)

从您的问题中,我们可以看出您的 javascript 正在尝试将某些文本解析为 JSON,但由于遇到无效字符 <.[=23 而失败了=]

您的视图代码有两个分支,具体取决于 hidden_checkbox 值是否在提交的表单中。

如果 hidden_checkbox 存在,视图 return 是序列化为 JSON 的响应。

如果 hidden_checkbox 不存在,视图 return 是一些 kml;由于 kml 是一种 xml 方言,所以它类似于 <kml>...</kml>.

您的 javascript 正在尝试将 kml 解析为 JSON,但失败了,因为 KML 无效 JSON。 (您可以通过在浏览器的 javascript 控制台中键入 JSON.parse('<kml></kml>') 来演示这一点 - 您会收到错误消息。)

我建议您在 javascript 中使用单独的事件处理程序,在 python 中使用两个单独的视图来处理两个提交按钮。

所以:

  • 如果按下第一个按钮,该按钮的 javascript 事件处理程序提交 POST 请求,视图 returns JSON,javascript 解析 JSON 并执行它应该做的任何事情。
  • 如果按下第二个按钮,该按钮的 javascript 处理程序会提交 POST 请求,视图 return 是 kml,javascript 不会尝试解析为 JSON 如果您的 headers 设置正确,下载应该会自动发生。

编辑:示例代码。

HTML

<form id="form" method="POST" action="/export-kml/">
    {% csrf_token %}

    <!-- Form fields here -->

    <!-- Handle clicking on this button with javascript -->
    <button type="button" value="Load Entities" data-action="/load-entities/">Load</button>

    <!-- Let the browser handle clicks on this button --> 
    <button type="submit" value="Export KML">Export</button>
</form>

Django 浏览量

def globe(request):
    """Handles retrieving items to be displayed on the virtual globe."""

    if request.method == 'POST':
        form = EntityGlobeForm(request.POST)

        #put items on the virtual globe
        if form.is_valid():

            #you are going to have to make a panel and paginate footprints 


            #object_list = ChangeDetectCSV.objects.filter(processing_level='RAW') #AND DATE

            sensor = form.cleaned_data.get('layer') #it is really sensor
            #if sensor is not 
            object_list = CesiumEntity.objects.filter(sensor = sensor)
            jdata= serialize('geojson', object_list,
                geometry_field='mpoly',
                fields=('name','file_name', 'id', 'dzi_location', 'country_code', 'corner_coords', 'sensor', 'targetName', 'collection_date'))

            return HttpResponse(json.dumps({'data': jdata}))

    else:
        form = EntityGlobeForm

    return render_to_response('swsite/sw_nga_globe.html', {'form':form },
        context_instance=RequestContext(request))


def export_kml(request):

    """Handles exporting KML file using information from the form."""

    if request.method == 'POST':
        form = EntityGlobeForm(request.POST)

        # Create the HttpResponse object with the appropriate KML.
        if form.is_valid():
            print 'building kml'
            kml = simplekml.Kml()
            kml.newpoint(name="Kirstenbosch", coords=[(18.432314,-33.988862)])  # lon, lat, optional height
            response = HttpResponse(kml.kml())
            response['Content-Disposition'] = 'attachment; filename="botanicalgarden.kml"'
            response['Content-Type'] = 'application/kml'
            print 'about to return response: ' + str(response)
            return response

    else:
        form = EntityGlobeForm

    return render_to_response('swsite/sw_nga_globe.html', {'form':form },
        context_instance=RequestContext(request))

javascript

$(document).ready(function () { 

    $('button[value="Load Entities"]').on('click', function () {
    // Submit the form to the url defined in the button's data-action attribute.
        console.log('Handling Loading Entities');
        var form = $('#form');
        $.ajax({
            type: form.prop('method'),''
            url: $(this).data('action'),
            data: form.serialize(),
            success: function (data) {
                // Do something with the returned data.
                console.log(data);
            } 
        });
    });

});

说明

我更改了表单,使其 action 属性指向处理 KML 导出的视图。 'Load Entities' 按钮被赋予了 data-action 属性指向处理 returning JSON 数据的视图(您必须更改这些 url 以匹配您的视图)。 'Export KML' 按钮的类型已更改为 submit,因此单击它会将表单提交到 KML 导出视图,而无需任何 javascript.

根据您问题中的代码,我简化了 globe 视图并添加了一个 export_kml 视图来处理导出 kml。现在我们正在使用两个 视图中不再需要 hidden_checkbox 逻辑(或在您的 javascript 中)。

您的 javascript 需要处理对 'Load Entities' 按钮的点击;我编写的 clickhandler 将表单提交到 globe 视图。

点击 'Export KML' 按钮由浏览器处理;这样,如果成功提交表单,KML 附件将是 return 并自动 由浏览器处理。处理 Ajax POST 请求中的附件非常棘手,最好让浏览器处理。