html前台提交form数据不跳转,并且获取返回信息

本文介绍如何使用HTML表单提交数据到PHP后台,同时不进行页面跳转,并通过jQuery.form.js插件实现获取服务器返回信息。在示例中,index.html中的表单数据被发送到test.php,且成功在控制台打印出提交信息。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
</head>
<body>

	<form id="themeForm" action="test.php"  method="post"  target="submitFrame" enctype="multipart/form-data" >
		<span class="file_parent">
		<!--去掉[] 单个上传 -->
		<input type="file" class="file" name="upload[]"  id="upload" multiple="multiple" /><br>
		</span>
		<input type="submit" value="上传">
		<input type="hidden" id="productid" name="productid" value="12345" /></br>
		<input type="hidden" id="str" name="str" value="你好啊" /></br>
	</form>
<!-- 将跳转页面转到看不见的iframe里面 并能取到相应返回数据 -->
<iframe  id="submitFrame" style="display: none;width:0; height:0" name="submitFrame"  src="about:blank"></iframe>
</body>
<script type="text/javascript" src="./js/jquery-2.1.0.js" ></script>
<script src="./js/jquery.form.js"></script>
<script>

 $("#themeForm").ajaxForm(function(re){
		console.log(re);
		alert("上传成功!");
});

</script>
</html>

我用的php作为事例接收
test.php

<?php
	//这里直接显示所有接收的文件对象和input字符串内容
	var_dump($_FILES);
	var_dump($_REQUEST);

	//下边是返回json格式的数据给自己留个备注而已,只需要index.html页面能获取到该页面的信息就够了
	// $arrays['info']=1;
	// echo (json_encode($arrays,JSON_UNESCAPED_UNICODE));
	// exit;
?>

jquery.form.js
官网也有 http://malsup.com/jquery/form/#download

/*!
 * jQuery Form Plugin
 * version: 3.51.0-2014.06.20
 * Requires jQuery v1.5 or later
 * Copyright (c) 2014 M. Alsup
 * Examples and documentation at: http://malsup.com/jquery/form/
 * Project repository: https://github.com/malsup/form
 * Dual licensed under the MIT and GPL licenses.
 * https://github.com/malsup/form#copyright-and-license
 */
/*global ActiveXObject */

// AMD support
(function (factory) {
    "use strict";
    if (typeof define === 'function' && define.amd) {
        // using AMD; register as anon module
        define(['jquery'], factory);
    } else {
        // no AMD; invoke directly
        factory( (typeof(jQuery) != 'undefined') ? jQuery : window.Zepto );
    }
}

(function($) {
"use strict";

/*
    Usage Note:
    -----------
    Do not use both ajaxSubmit and ajaxForm on the same form.  These
    functions are mutually exclusive.  Use ajaxSubmit if you want
    to bind your own submit handler to the form.  For example,

    $(document).ready(function() {
        $('#myForm').on('submit', function(e) {
            e.preventDefault(); // <-- important
            $(this).ajaxSubmit({
                target: '#output'
            });
        });
    });

    Use ajaxForm when you want the plugin to manage all the event binding
    for you.  For example,

    $(document).ready(function() {
        $('#myForm').ajaxForm({
            target: '#output'
        });
    });

    You can also use ajaxForm with delegation (requires jQuery v1.7+), so the
    form does not have to exist when you invoke ajaxForm:

    $('#myForm').ajaxForm({
        delegation: true,
        target: '#output'
    });

    When using ajaxForm, the ajaxSubmit function will be invoked for you
    at the appropriate time.
*/

/**
 * Feature detection
 */
var feature = {};
feature.fileapi = $("<input type='file'/>").get(0).files !== undefined;
feature.formdata = window.FormData !== undefined;

var hasProp = !!$.fn.prop;

// attr2 uses prop when it can but checks the return type for
// an expected string.  this accounts for the case where a form 
// contains inputs with names like "action" or "method"; in those
// cases "prop" returns the element
$.fn.attr2 = function() {
    if ( ! hasProp ) {
        return this.attr.apply(this, arguments);
    }
    var val = this.prop.apply(this, arguments);
    if ( ( val && val.jquery ) || typeof val === 'string' ) {
        return val;
    }
    return this.attr.apply(this, arguments);
};

/**
 * ajaxSubmit() provides a mechanism for immediately submitting
 * an HTML form using AJAX.
 */
$.fn.ajaxSubmit = function(options) {
    /*jshint scripturl:true */

    // fast fail if nothing selected (http://dev.jquery.com/ticket/2752)
    if (!this.length) {
        log('ajaxSubmit: skipping submit process - no element selected');
        return this;
    }

    var method, action, url, $form = this;

    if (typeof options == 'function') {
        options = { success: options };
    }
    else if ( options === undefined ) {
        options = {};
    }

    method = options.type || this.attr2('method');
    action = options.url  || this.attr2('action');

    url = (typeof action === 'string') ? $.trim(action) : '';
    url = url || window.location.href || '';
    if (url) {
        // clean url (don't include hash vaue)
        url = (url.match(/^([^#]+)/)||[])[1];
    }

    options = $.extend(true, {
        url:  url,
        success: $.ajaxSettings.success,
        type: method || $.ajaxSettings.type,
        iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank'
    }, options);

    // hook for manipulating the form data before it is extracted;
    // convenient for use with rich editors like tinyMCE or FCKEditor
    var veto = {};
    this.trigger('form-pre-serialize', [this, options, veto]);
    if (veto.veto) {
        log('ajaxSubmit: submit vetoed via form-pre-serialize trigger');
        return this;
    }

    // provide opportunity to alter form data before it is serialized
    if (options.beforeSerialize && options.beforeSerialize(this, options) === false) {
        log('ajaxSubmit: submit aborted via beforeSerialize callback');
        return this;
    }

    var traditional = options.traditional;
    if ( traditional === undefined ) {
        traditional = $.ajaxSettings.traditional;
    }

    var elements = [];
    var qx, a = this.formToArray(options.semantic, elements);
    if (options.data) {
        options.extraData = options.data;
        qx = $.param(options.data, traditional);
    }

    // give pre-submit callback an opportunity to abort the submit
    if (options.beforeSubmit && options.beforeSubmit(a, this, options) === false) {
        log('ajaxSubmit: submit aborted via beforeSubmit callback');
        return this;
    }

    // fire vetoable 'validate' event
    this.trigger('form-submit-validate', [a, this, options, veto]);
    if (veto.veto) {
        log('ajaxSubmit: submit vetoed via form-submit-validate trigger');
        return this;
    }

    var q = $.param(a, traditional);
    if (qx) {
        q = ( q ? (q + '&' + qx) : qx );
    }
    if (options.type.toUpperCase() == 'GET') {
        options.url += (options.url.indexOf('?') >= 0 ? '&' : '?') + q;
        options.data = null;  // data is null for 'get'
    }
    else {
        options.data = q; // data is the query string for 'post'
    }

    var callbacks = [];
    if (options.resetForm) {
        callbacks.push(function() { $form.resetForm(); });
    }
    if (options.clearForm) {
        callbacks.push(function() { $form.clearForm(options.includeHidden); });
    }

    // perform a load on the target only if dataType is not provided
    if (!options.dataType && options.target) {
        var oldSuccess = options.success || function(){};
        callbacks.push(function(data) {
            var fn = options.replaceTarget ? 'replaceWith' : 'html';
            $(options.target)[fn](data).each(oldSuccess, arguments);
        });
    }
    else if (options.success) {
        callbacks.push(options.success);
    }

    options.success = function(data, status, xhr) { // jQuery 1.4+ passes xhr as 3rd arg
        var context = options.context || this ;    // jQuery 1.4+ supports scope context
        for (var i=0, max=callbacks.length; i < max; i++) {
            callbacks[i].apply(context, [data, status, xhr || $form, $form]);
        }
    };

    if (options.error) {
        var oldError = options.error;
        options.error = function(xhr, status, error) {
            var context = options.context || this;
            oldError.apply(context, [xhr, status, error, $form]);
        };
    }

     if (options.complete) {
        var oldComplete = options.complete;
        options.complete = function(xhr, status) {
            var context = options.context || this;
            oldComplete.apply(context, [xhr, status, $form]);
        };
    }

    // are there files to upload?

    // [value] (issue #113), also see comment:
    // https://github.com/malsup/form/commit/588306aedba1de01388032d5f42a60159eea9228#commitcomment-2180219
    var fileInputs = $('input[type=file]:enabled', this).filter(function() { return $(this).val() !== ''; });

    var hasFileInputs = fileInputs.length > 0;
    var mp = 'multipart/form-data';
    var multipart = ($form.attr('enctype') == mp || $form.attr('encoding') == mp);

    var fileAPI = feature.fileapi && feature.formdata;
    log("fileAPI :" + fileAPI);
    var shouldUseFrame = (hasFileInputs || multipart) && !fileAPI;

    var jqxhr;

    // op
<think>我们根据用户的问题,需要实现一个功能:前端输入条件,后端根据条件查询数据库,生成Excel文件供用户下载。根据引用[4]中的思路,由于ajax能直接处理文件流,我们可以采用以下步骤:1.前端通过表单或ajax发送查询条件到后端。2.后端根据条件查询数据库,生成Excel文件并保存到服务器的临时目录,同时生成一个唯一的文件名(避免并发冲突)。3.后端将生成的Excel文件的下载URL返回给前端(可以是临时文件的URL,或者通过一个视图来提供下载)。4.前端接收到URL后,通过window.location.href或创建a标签的方式触发下载。但是,我们也可以有另一种更直接的方式(需要保存到服务器临时文件):1.前端提交条件(可以是GET或POST)。2.后端查询数据,直接在内存中生成Excel文件,然后通过HttpResponse返回文件流(需要保存到服务器文件系统)。3.这样就需要返回URL,而是直接返回文件流,前端直接触发下载。两种方式比较:第一种(保存到临时文件)适用于大文件生成,避免长时间占用请求进程,并且可以支持异步生成(比如用Celery),然后通知前端下载。第二种(直接返回文件流)简单快捷,适合数据是特别大的情况。这里我们主要介绍第二种方式,因为更常见简单。但如果数据量非常大,建议采用第一种方式并配合异步任务。实现步骤:后端(Django):1.创建一个视图,接收前端提交的查询条件(GET或POST请求)。2.解析条件,过滤数据库查询集。3.使用openpyxl(或其他库)创建Excel文件,将查询结果写入。4.将Excel文件写入HttpResponse,设置正确的Content-Type和Content-Disposition,返回给前端。前端:1.用户输入条件,点击导出按钮。2.将条件通过表单提交(直接跳转)或ajax提交(然后根据返回的URL触发下载)到后端视图。注意:如果使用ajax提交,由于ajax能直接下载文件,所以我们可以采用以下两种方式之一:-使用ajax,而是使用表单提交表单的action指向我们的导出视图,这样可以直接触发下载。-使用ajax提交条件,后端生成文件后返回一个URL(比如临时文件的URL),然后前端通过window.location.href=url来下载。这里我们先介绍使用表单提交的方式(简单直接),然后介绍使用ajax的方式。方式一:表单提交(推荐简单场景)步骤:1.前端使用form表单,用户输入条件,点击提交按钮。2.表单的method可以是GET或POST,action指向导出视图的URL。3.后端视图处理条件,生成Excel文件并返回。方式二:ajax提交(适用于需要先验证条件等复杂场景)步骤:1.前端通过ajax将条件发送到后端。2.后端生成Excel文件并保存到临时目录(比如media/temp/),然后返回临时文件的URL(或者返回一个可以下载该文件的视图URL,带文件名字参数)。3.前端收到URL后,触发下载(例如:window.location.href= url)。但是,根据引用[4]中的经验,ajax能直接处理文件流,所以能直接返回文件流给ajax。因此,我们采用返回临时文件URL的方式。下面分别实现这两种方式。我们先实现方式一(表单提交直接下载):后端视图(views.py)示例: ```pythonfromdjango.httpimport HttpResponsefromopenpyxl importWorkbookfrom .models importYourModelfromdjango.shortcuts importrenderdef export_excel(request):#获取前端传来的查询条件(这里假设条件通过GET请求传递,也可以使用POST)#例如:/export-excel/?name=John&min_age=20name_filter= request.GET.get('name', '')min_age= request.GET.get('min_age',None)#构建查询集queryset =YourModel.objects.all()if name_filter:queryset =queryset.filter(name__icontains=name_filter)ifmin_age:queryset= queryset.filter(age__gte=int(min_age))#创建Excel工作簿wb =Workbook()ws= wb.activews.title= "数据导出"#写入表头headers =['ID', '姓名','年龄', '邮箱']#替换为你的模型字段ws.append(headers)#写入数据forobj inqueryset:row =[obj.id,obj.name, obj.age,obj.email]ws.append(row)#设置HTTP响应类型response =HttpResponse(content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')#设置文件名,这里可以按条件命名filename =f"export_{name_filter}_{min_age}.xlsx"if name_filter ormin_ageelse "export_all.xlsx"response['Content-Disposition'] =f'attachment;filename={filename}'#将工作簿保存到响应wb.save(response)return response```前端表单HTML)示例: ```html<form action="{% url'export_excel' %}" method="get"><inputtype="text"name="name"placeholder="姓名"><input type="number" name="min_age"placeholder="最小年龄"><buttontype="submit">导出Excel</button> </form>```方式二:使用ajax提交,后端生成临时文件并返回URL后端视图(views.py)示例: ```pythonimport osimportuuidfrom django.conf importsettingsfrom django.http importJsonResponsefromopenpyxl importWorkbookdefexport_excel_ajax(request):if request.method =='POST':#获取条件(假设通过POST)name_filter =request.POST.get('name','')min_age =request.POST.get('min_age', None)#构建查询集(同上)queryset= YourModel.objects.all()ifname_filter:queryset= queryset.filter(name__icontains=name_filter)if min_age:queryset =queryset.filter(age__gte=int(min_age))#创建Excelwb =Workbook()ws= wb.activews.title= "数据导出"headers =['ID', '姓名','年龄', '邮箱']ws.append(headers)forobj inqueryset:row =[obj.id,obj.name, obj.age,obj.email]ws.append(row)#保存到临时文件temp_dir= os.path.join(settings.MEDIA_ROOT, 'temp')ifnot os.path.exists(temp_dir):os.makedirs(temp_dir)filename =f"{uuid.uuid4().hex}.xlsx"#生成唯一文件名file_path= os.path.join(temp_dir, filename)wb.save(file_path)#返回临时文件的下载URLfile_url =f"{settings.MEDIA_URL}temp/{filename}"returnJsonResponse({'status': 'success','file_url':file_url})return JsonResponse({'status':'error', 'message':'Invalidrequest'})```前端(HTML和JavaScript)示例:```html<formid="exportForm">{% csrf_token%}<inputtype="text"name="name"placeholder="姓名"><inputtype="number"name="min_age" placeholder="最小年龄"><button type="button" onclick="exportExcel()">导出Excel</button></form> <script> functionexportExcel() {varformData= newFormData(document.getElementById('exportForm'));fetch('{% url"export_excel_ajax" %}', {method: 'POST',body: formData}).then(response=> response.json()).then(data=> {if(data.status ==='success') {//触发下载window.location.href =data.file_url;}else {alert('导出失败');}}).catch(error=> console.error('Error:',error));} </script>```注意:第二种方式需要Django配置MEDIA_ROOT和MEDIA_URL,并且确保临时目录可以通过URL访问(即MEDIA_URL对应的路径由Django处理静态文件服务)。在生产环境中,通常由Web服务器(如Nginx)提供静态文件服务。另外,临时文件需要定期清理,可以设置一个定时任务(比如cron)或者每次生成前清理旧文件。根据用户需求,我们更推荐第一种方式(表单直接提交),因为它更简单,需要处理临时文件。但如果需要更复杂的交互(比如先验证条件,再导出),则可以使用第二种方式。最后,配置URL:```python#urls.pyfrom django.urls importpathfrom .import viewsurlpatterns =[path('export-excel/',views.export_excel,name='export_excel'),path('export-excel-ajax/', views.export_excel_ajax, name='export_excel_ajax'), ]```以上两种方式都可以实现根据前端输入条件查询数据库并生成Excel文件。注意:在第二种方式中,由于我们使用了临时文件,需要确保服务器有足够的存储空间,并且要处理文件清理。可以在生成文件时记录生成时间,然后定期删除超过一定时间的临时文件。另外,如果数据量非常大,建议使用异步任务(例如Celery)来生成文件,然后通过邮件或通知提供下载链接。但这超出了当前问题的范围。希望这个回答能够帮助用户解决问题。</think>根据您的需求,我将详细介绍如何在Django中根据前端输入条件查询数据库并生成Excel文件的完整解决方案。以下是实现步骤: ### 完整解决方案 #### 1. 后端实现(Django视图) ```python # views.py from django.http import HttpResponse, JsonResponse from openpyxl import Workbook from .models import YourModel import os from django.conf import settings import uuid from django.utils import timezone def export_excel(request): # 获取前端查询条件 search_params = { 'name': request.POST.get('name', ''), 'min_age': request.POST.get('min_age'), 'max_age': request.POST.get('max_age'), 'status': request.POST.get('status', 'active') } # 构建查询集 queryset = YourModel.objects.all() # 应用筛选条件 if search_params['name']: queryset = queryset.filter(name__icontains=search_params['name']) if search_params['min_age']: queryset = queryset.filter(age__gte=int(search_params['min_age'])) if search_params['max_age']: queryset = queryset.filter(age__lte=int(search_params['max_age'])) if search_params['status'] != 'all': queryset = queryset.filter(status=search_params['status']) # 创建Excel文件 wb = Workbook() ws = wb.active ws.title = "筛选结果" # 添加表头 headers = ["ID", "姓名", "年龄", "邮箱", "状态", "创建时间"] ws.append(headers) # 填充数据 for obj in queryset: row = [ obj.id, obj.name, obj.age, obj.email, obj.get_status_display(), obj.created_at.strftime("%Y-%m-%d %H:%M") ] ws.append(row) # 保存到临时文件 temp_dir = os.path.join(settings.MEDIA_ROOT, 'temp_exports') os.makedirs(temp_dir, exist_ok=True) filename = f"export_{timezone.now().strftime('%Y%m%d_%H%M%S')}_{uuid.uuid4().hex[:6]}.xlsx" filepath = os.path.join(temp_dir, filename) wb.save(filepath) # 返回文件路径 file_url = f"{settings.MEDIA_URL}temp_exports/{filename}" return JsonResponse({'file_url': file_url}) ``` #### 2. URL配置 ```python # urls.py from django.urls import path from .views import export_excel urlpatterns = [ path('export-excel/', export_excel, name='export_excel'), ] ``` #### 3. 前端实现(HTML + JavaScript) ```html <!-- 筛选表单 --> <form id="exportForm"> {% csrf_token %} <div> <label>姓名:</label> <input type="text" name="name"> </div> <div> <label>年龄范围:</label> <input type="number" name="min_age" placeholder="最小年龄"> <input type="number" name="max_age" placeholder="最大年龄"> </div> <div> <label>状态:</label> <select name="status"> <option value="active">活跃</option> <option value="inactive">活跃</option> <option value="all">全部</option> </select> </div> <button type="button" onclick="exportData()">导出Excel</button> </form> <script> function exportData() { const form = document.getElementById('exportForm'); const formData = new FormData(form); fetch('/export-excel/', { method: 'POST', body: formData }) .then(response => response.json()) .then(data => { if (data.file_url) { // 创建临时下载链接 const link = document.createElement('a'); link.href = data.file_url; link.download = 'exported_data.xlsx'; document.body.appendChild(link); link.click(); document.body.removeChild(link); // 可选:清理旧文件(通过另一个API) cleanupOldExports(); } }) .catch(error => console.error('导出失败:', error)); } // 清理过期文件(可选) function cleanupOldExports() { fetch('/cleanup-exports/', { method: 'POST' }) .then(response => response.json()) .then(data => console.log('清理完成:', data.message)); } </script> ``` #### 4. 文件清理任务(可选) ```python # views.py import os import glob from datetime import datetime, timedelta def cleanup_old_exports(request): temp_dir = os.path.join(settings.MEDIA_ROOT, 'temp_exports') now = datetime.now() deleted_count = 0 for filepath in glob.glob(os.path.join(temp_dir, '*.xlsx')): file_time = datetime.fromtimestamp(os.path.getctime(filepath)) if now - file_time > timedelta(hours=1): # 删除超过1小时的文件 try: os.remove(filepath) deleted_count += 1 except Exception as e: print(f"删除失败 {filepath}: {e}") return JsonResponse({ 'status': 'success', 'message': f'已清理 {deleted_count} 个旧文件' }) ``` ### 关键实现要点 1. **条件筛选处理**: - 前端通过表单提交筛选条件 - 后端使用`filter()`方法构建动态查询集 - 支持文本、数字范围和状态筛选 2. **文件生成流程**: - 使用`openpyxl`创建Excel工作簿 - 添加动态表头和筛选后的数据 - 生成唯一文件名防止冲突 - 保存到临时目录(`MEDIA_ROOT/temp_exports`) 3. **文件下载机制**: - 后端返回文件URL给前端 - 前端创建隐藏的`<a>`标签触发下载 - 避免直接通过ajax处理文件流 4. **资源管理**: - 使用UUID和时间戳生成唯一文件名 - 定期清理旧文件(通过定时任务或每次导出后触发) - 设置文件有效期(示例中为1小时) ### 优化建议 1. **大数据量处理**: ```python # 使用分页和迭代器 page_size = 5000 total = queryset.count() for offset in range(0, total, page_size): page = queryset[offset:offset+page_size] for obj in page.iterator(): # 处理数据... ``` 2. **异步任务**(使用Celery): ```python from celery import shared_task @shared_task def async_export_task(params, user_email): # 执行导出逻辑... # 完成后发送邮件通知 send_mail( '导出完成通知', f'您的Excel文件已准备好:{file_url}', '[email protected]', [user_email] ) ``` 3. **安全增强**: ```python # 限制导出频率 from django.core.cache import cache user_id = request.user.id if cache.get(f'export_lock_{user_id}'): return JsonResponse({'error': '操作过于频繁,请稍后再试'}, status=429) cache.set(f'export_lock_{user_id}', True, timeout=300) # 5分钟冷却 ``` ### 相关配置 确保在`settings.py`中配置媒体文件: ```python MEDIA_URL = '/media/' MEDIA_ROOT = os.path.join(BASE_DIR, 'media') ``` 在`urls.py`中添加媒体文件服务(仅开发环境): ```python from django.conf import settings from django.conf.urls.static import static if settings.DEBUG: urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) ``` 此方案实现了根据前端条件筛选数据并导出Excel的完整流程,包含文件管理和优化建议,适合各种规模的Django应用[^1][^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值