Django Ajax、批量操作与分页实践
Django Ajax、批量操作与分页实践本章介绍不刷新整页的异步请求、文件上传、批量写入、JSON 序列化和分页。它们共同服务于更流畅的交互体验但仍必须遵循 HTTP 方法、CSRF、防护、数据校验和数据库性能等基本规则。一、Ajax 的作用与请求边界AjaxAsynchronous JavaScript and XML是浏览器通过 JavaScript 主动发起 HTTP 请求、拿到结果后仅更新局部页面的技术集合。现代请求通常传输 JSON 或表单数据而不是 XML。Ajax 不等于“没有页面跳转”而是由前端决定如何处理服务器响应。方式触发方式常见结果地址栏、a浏览器导航整页加载新的页面form原生提交GET 或 POST浏览器按响应导航或刷新Ajax / FetchJavaScript 调用前端根据响应局部更新页面Ajax 仍然是普通 HTTP 请求GET 用于读取POST/PUT/PATCH/DELETE 用于改变数据。后端必须像处理普通表单一样完成认证、权限和输入校验。二、返回 JSON使用 JsonResponse浏览器与 Django 之间交换结构化数据时JSON 是最常用格式。Python 字典不是 JSON 字符串推荐使用JsonResponse自动序列化并设置application/json响应头。# user/views.pyfromdjango.httpimportJsonResponsefromdjango.viewsimportViewclassRegisterView(View):defget(self,request,*args,**kwargs):returnrender(request,user/register.html)defpost(self,request,*args,**kwargs):usernamerequest.POST.get(username,).strip()passwordrequest.POST.get(password,)ifnotusernameornotpassword:returnJsonResponse({ok:False,error:用户名和密码不能为空,},status400)# 此处应使用 Django 认证系统处理密码不能明文保存。returnJsonResponse({ok:True,message:注册成功},status201)代码说明JSON 响应建议使用统一字段例如ok、data、error并配合合适 HTTP 状态码。不要用HttpResponse(dict)直接返回字典若手动使用json.dumps()还需自行正确设置content_type。三、jQuery Ajax 提交普通表单数据jQuery 的$.ajax()传入普通对象时默认以application/x-www-form-urlencoded形式编码因此 Django 可从request.POST读取数据。它并不会自动发送 JSON。POST 请求必须携带 Django 的 CSRF Token。模板中先输出{% csrf_token %}再从隐藏输入框读取令牌并放入请求头是较清晰的做法。!-- user/templates/user/register.html --{% load static %}scriptsrc{% static js/jquery.min.js %}/scriptformidregister-form{% csrf_token %}label用户名inputidusernamenameusernamerequired/labellabel密码inputidpasswordnamepasswordtypepasswordrequired/labelbuttonidsubmit-buttontypesubmit注册/button/formpidmessagerolestatus/p$(#register-form).on(submit,function(event){event.preventDefault();constcsrfToken$([namecsrfmiddlewaretoken]).val();$.ajax({url:window.location.pathname,type:POST,data:{username:$(#username).val(),password:$(#password).val(),},headers:{X-CSRFToken:csrfToken},dataType:json,}).done(function(data){$(#message).text(data.message);}).fail(function(xhr){constmessagexhr.responseJSON?.error||请求失败请稍后重试;$(#message).text(message);});});代码说明dataType: json表示期望服务端响应是 JSON并不会改变请求体编码。表单提交事件中调用event.preventDefault()可以阻止浏览器原生整页提交。success回调只处理成功状态使用.fail()或error回调才能处理 4xx/5xx 响应。发送 JSON 请求体当 API 明确约定使用 JSON 时应把对象序列化为字符串设置contentType: application/json并在 Django 中从request.body读取和解析。$.ajax({url:/api/calculate/,type:POST,contentType:application/json,dataType:json,headers:{X-CSRFToken:$([namecsrfmiddlewaretoken]).val()},data:JSON.stringify({number_one:12,number_two:3,operator:}),});importjsonfromdjango.httpimportJsonResponsedefcalculate(request):try:payloadjson.loads(request.body)leftfloat(payload[number_one])rightfloat(payload[number_two])except(KeyError,TypeError,ValueError,json.JSONDecodeError):returnJsonResponse({ok:False,error:参数格式错误},status400)operatorpayload.get(operator)operations{:lambda:leftright,-:lambda:left-right,*:lambda:left*right,/:lambda:left/rightifright!0elseNone,}ifoperatornotinoperations:returnJsonResponse({ok:False,error:不支持的运算符},status400)resultoperations[operator]()ifresultisNone:returnJsonResponse({ok:False,error:除数不能为 0},status400)returnJsonResponse({ok:True,result:result})代码说明解析 JSON 时应捕获格式错误并验证数据类型。涉及金额时不要使用float应使用Decimal此处仅用于简单计算示例。四、Ajax 上传文件FormData文件不能作为普通对象字段可靠地发送。浏览器需要用FormData生成multipart/form-data请求体Django 则从request.FILES读取上传文件文本字段仍在request.POST。formidavatar-form{% csrf_token %}label用户名inputidusernamenameusername/labellabel头像inputidavatarnameavatartypefileacceptimage/*/labelbuttontypesubmit上传/button/formpidupload-messagerolestatus/p$(#avatar-form).on(submit,function(event){event.preventDefault();constformDatanewFormData(this);$.ajax({url:window.location.pathname,type:POST,data:formData,processData:false,contentType:false,headers:{X-CSRFToken:$([namecsrfmiddlewaretoken]).val()},dataType:json,}).done((data)$(#upload-message).text(data.message)).fail((xhr)$(#upload-message).text(xhr.responseJSON?.error||上传失败));});fromdjango.httpimportJsonResponsedefupload_avatar(request):ifrequest.method!POST:returnJsonResponse({error:仅支持 POST},status405)avatarrequest.FILES.get(avatar)ifavatarisNone:returnJsonResponse({ok:False,error:请选择文件},status400)ifavatar.size5*1024*1024:returnJsonResponse({ok:False,error:文件不能超过 5 MB},status400)# 还应校验真实内容、扩展名和权限并使用受控存储后端保存。returnJsonResponse({ok:True,message:文件已接收})代码说明processData: false防止 jQuery 将FormData转成查询字符串contentType: false让浏览器自动生成带边界的 multipart 请求头。不要试图读取文件输入框的.val()作为真实路径浏览器会刻意隐藏本地路径。request.is_ajax()已在 Django 3.1 弃用并在后续版本移除不应使用它判断请求类型。若业务确实需要特定标记可以检查自定义请求头但接口应以响应格式和 HTTP 约定为准而不是把“是否 Ajax”作为安全边界。五、确认弹窗与安全删除确认弹窗只能改善用户体验不能代替后端权限校验。删除操作必须使用 POST 或 DELETE不能使用 GET因为 GET 应保持安全且幂等不应改变服务器数据。tableidbook-tabletrdata-book-id1td西游记/tdtdbuttonclassdelete-booktypebutton删除/button/td/tr/table$(#book-table).on(click,.delete-book,function(){constrow$(this).closest(tr);constbookIdrow.data(book-id);if(!window.confirm(确定删除这本书吗)){return;}$.ajax({url:/books/${bookId}/delete/,type:POST,headers:{X-CSRFToken:$([namecsrfmiddlewaretoken]).val()},dataType:json,}).done(function(data){if(data.ok)row.remove();}).fail(function(xhr){alert(xhr.responseJSON?.error||删除失败);});});fromdjango.contrib.auth.decoratorsimportlogin_requiredfromdjango.httpimportJsonResponsefromdjango.views.decorators.httpimportrequire_POSTfrom.modelsimportBooklogin_requiredrequire_POSTdefdelete_book(request,book_id):bookBook.objects.filter(pkbook_id).first()ifbookisNone:returnJsonResponse({ok:False,error:图书不存在},status404)# 此处还应校验 request.user 是否有删除该图书的权限。book.delete()returnJsonResponse({ok:True})代码说明页面中重复项应使用 class 而不是重复的 id。事件委托绑定到表格父元素即使后续动态添加按钮也能响应点击。SweetAlert、layer 等组件可以替代window.confirm()但后端的登录、权限、CSRF 和请求方法限制始终不可省略。六、批量插入bulk_create()逐条调用create()会执行大量 INSERT 语句导入大量数据时bulk_create()可以显著减少数据库往返次数。它应使用分批写入避免一次性创建过多 Python 对象或超出数据库参数限制。fromdecimalimportDecimalfromdjango.dbimporttransactionfrom.modelsimportBookdefimport_books(rows):batch_size1000batch[]withtransaction.atomic():forindex,rowinenumerate(rows,start1):batch.append(Book(namerow[name],priceDecimal(str(row[price])),))iflen(batch)batch_size:Book.objects.bulk_create(batch,batch_sizebatch_size)batch.clear()ifbatch:Book.objects.bulk_create(batch,batch_sizebatch_size)代码说明bulk_create()通常不会调用每个对象的save()也不会发送pre_save、post_save信号依赖这些钩子的业务逻辑需要额外处理。示例使用Decimal(str(...))避免浮点数精度问题。百万级数据导入还应考虑后台任务、进度反馈、失败重试和数据库锁影响不能直接阻塞普通 Web 请求。七、把 QuerySet 序列化为 JSON模型实例和QuerySet不能直接交给JsonResponse。接口应明确选择要公开的字段转换为基础数据类型后再返回这样既能控制响应结构也能避免泄露敏感字段。fromdjango.httpimportJsonResponsefrom.modelsimportBookdefbook_list_api(request):bookslist(Book.objects.values(id,name,price)[:100])returnJsonResponse({results:books})代码说明values()返回字典形式的QuerySetlist()触发查询并得到可 JSON 序列化的列表。返回对象包一层results可在以后添加分页、统计信息或错误字段而不破坏接口结构。django.core.serializers.serialize(json, queryset)也可将模型序列化为 JSON但输出结构包含模型标签、主键和fields嵌套通常不适合作为面向前端的稳定 API。复杂 API 更适合使用 Django REST Framework 的 Serializer 明确控制字段和验证规则。八、分页使用 Django Paginator分页避免一次性向数据库和页面加载所有记录。最基础的切片公式是第page页、每页per_page条数据对应[ (page - 1) * per_page : page * per_page ]。但业务项目应优先使用 Django 的Paginator它处理页码、总页数、边界与异常更可靠。fromdjango.core.paginatorimportEmptyPage,PageNotAnInteger,Paginatorfromdjango.shortcutsimportrenderfrom.modelsimportBookdefbook_list(request):booksBook.objects.order_by(id)paginatorPaginator(books,20)page_numberrequest.GET.get(page,1)try:page_objpaginator.page(page_number)exceptPageNotAnInteger:page_objpaginator.page(1)exceptEmptyPage:page_objpaginator.page(paginator.num_pages)returnrender(request,book/list.html,{page_obj:page_obj})!-- book/templates/book/list.html --ul{% for book in page_obj.object_list %}li{{ book.name }} - {{ book.price }}/li{% empty %}li暂无图书/li{% endfor %}/ulnavaria-label图书分页ulclasspagination{% if page_obj.has_previous %}liahref?page1首页/a/liliahref?page{{ page_obj.previous_page_number }}上一页/a/li{% endif %} {% for page in page_obj.paginator.get_elided_page_range %} {% if page page_obj.paginator.ELLIPSIS %}liclassdisabledspan{{ page }}/span/li{% elif page page_obj.number %}liclassactivespan{{ page }}/span/li{% else %}liahref?page{{ page }}{{ page }}/a/li{% endif %} {% endfor %} {% if page_obj.has_next %}liahref?page{{ page_obj.next_page_number }}下一页/a/liliahref?page{{ page_obj.paginator.num_pages }}尾页/a/li{% endif %}/ul/nav代码说明Paginator会对QuerySet做切片从而生成带LIMIT和OFFSET的查询。get_elided_page_range可在页数很多时显示省略号避免模板手写大量嵌套判断。深页码的 OFFSET 查询在超大表上可能变慢这时应考虑基于游标或主键的“键集分页”。九、实践要点Ajax 请求仍是 HTTP 请求后端必须校验方法、权限、CSRF 与输入数据。jQuery 普通对象默认发的是表单编码发送 JSON 时需JSON.stringify()和contentType: application/json。上传文件使用FormData文件从request.FILES读取并在服务端限制大小、类型和存储位置。所有删除、创建和更新操作使用非 GET 方法确认弹窗不能替代服务器权限控制。大批量写入分批bulk_create()理解它不会触发save()和模型信号。接口只返回必要字段分页优先使用Paginator而不是拼接带safe的 HTML 字符串。掌握这些做法后页面交互、数据导入和列表展示可以在保持响应速度的同时维持清晰的安全与维护边界。

相关新闻

网络摄像机RTSP地址与端口配置实战:从原理到排查全解析

网络摄像机RTSP地址与端口配置实战:从原理到排查全解析

1. 项目概述:从“连不上”到“看得见”的实战之路最近在折腾家里的安防监控,想把几个不同品牌的网络摄像机画面集成到NAS或者智能家居平台上,结果第一步就卡住了——找不到摄像机的RTSP地址和端口。这感觉就像你拿到了一把新房的钥匙&#xf…

2026/8/16 22:52:24 阅读更多 →
NDIS驱动层网络过滤实战:构建终端违规外联的底层防线

NDIS驱动层网络过滤实战:构建终端违规外联的底层防线

1. 项目概述:从“违规外联”到“合规管控”的实战思考最近在和一些做企业安全运维的朋友聊天时,大家不约而同地提到了一个让人头疼的老大难问题——“违规外联”。这个词听起来有点专业,说白了,就是公司内网里的电脑,未…

2026/8/18 0:02:46 阅读更多 →
SkillShapley:基于边界自适应Shapley值的大模型智能体技能步骤归因方法

SkillShapley:基于边界自适应Shapley值的大模型智能体技能步骤归因方法

1. 项目概述:当大模型智能体学会“论功行赏” 最近在折腾大模型智能体(LLM Agents)的朋友,估计都遇到过同一个灵魂拷问:当你的智能体完成一个复杂任务,比如写一份市场分析报告,或者调试一段代码…

2026/8/16 22:52:24 阅读更多 →

最新新闻

图像修复智能体:从多任务学习到顺序感知决策的技术演进

图像修复智能体:从多任务学习到顺序感知决策的技术演进

1. 从“修图”到“智能体”:图像修复的范式革命最近在图像处理圈子里,一个叫 DiTTo 的项目讨论度挺高。光看标题 “Scalable Order-aware All-in-One Image Restoration Agent”, 信息量就很大。它不像我们熟悉的那些“一键去噪”、“超分辨率…

2026/8/18 1:03:31 阅读更多 →
汽车零部件质量困局:从电子电气到动力总成的故障分析与应对策略

汽车零部件质量困局:从电子电气到动力总成的故障分析与应对策略

1. 从“修不好”到“不敢买”:汽车投诉背后的零部件困局最近和几个做汽车后市场的朋友聊天,话题总绕不开一个现象:现在车主来店里,抱怨的已经不只是“车坏了”,而是“这个零件怎么又坏了”、“上次换的件才用了半年”、…

2026/8/18 1:03:31 阅读更多 →
新能源汽车动力电池选购指南:从电芯、BMS到安全与场景化选择

新能源汽车动力电池选购指南:从电芯、BMS到安全与场景化选择

1. 从“里程焦虑”到“电池焦虑”:为什么选车先看电池?如果你最近在看新能源车,尤其是纯电车型,大概率会听到销售顾问反复强调一个词:续航。但“续航”这个数字背后,真正决定你用车体验、钱包厚度甚至车辆残…

2026/8/18 1:03:31 阅读更多 →
Android 时间选择器终极定制指南:一步步用 PickerView 打造顺手的日期时间控件

Android 时间选择器终极定制指南:一步步用 PickerView 打造顺手的日期时间控件

Android 时间选择器终极定制指南:一步步用 PickerView 打造顺手的日期时间控件 【免费下载链接】Android-PickerView This is a picker view for android , support linkage effect, timepicker and optionspicker.(时间选择器、省市区三级联动&#xff…

2026/8/18 1:03:31 阅读更多 →
构建行为自适应对话智能体:从静态人格到流体人格框架的工程实践

构建行为自适应对话智能体:从静态人格到流体人格框架的工程实践

1. 从“千人一面”到“千人千面”:对话智能体的个性困境与破局点 最近在折腾大语言模型应用落地的朋友,估计都绕不开一个核心问题:我们费尽心思调教出来的AI助手,怎么总感觉“味儿不对”?无论是客服机器人、虚拟陪伴助…

2026/8/18 1:03:31 阅读更多 →
Coze工作流实战:从零构建智能简历筛选助手,掌握AI应用工程化核心

Coze工作流实战:从零构建智能简历筛选助手,掌握AI应用工程化核心

如果你最近关注AI应用开发,可能会发现一个现象:很多教程都在讲“零代码搭建AI应用”,但当你真正上手时,却发现要么是功能过于简单,要么是遇到复杂逻辑就束手无策。问题出在哪里?核心在于,大多数…

2026/8/18 1:02:31 阅读更多 →

日新闻

告别逐帧截图:用 extract-video-ppt 快速提取视频中的 PPT 并一键导出 PDF

告别逐帧截图:用 extract-video-ppt 快速提取视频中的 PPT 并一键导出 PDF

告别逐帧截图:用 extract-video-ppt 快速提取视频中的 PPT 并一键导出 PDF 【免费下载链接】extract-video-ppt extract the ppt in the video 项目地址: https://gitcode.com/gh_mirrors/ex/extract-video-ppt 如果你还停留在"看网课 不停暂停 截图 …

2026/8/18 0:00:57 阅读更多 →
思源宋体TTF一站式上手:7个字重免费商用,从下载到上线的完整走查

思源宋体TTF一站式上手:7个字重免费商用,从下载到上线的完整走查

思源宋体TTF一站式上手:7个字重免费商用,从下载到上线的完整走查 【免费下载链接】source-han-serif-ttf Source Han Serif TTF 项目地址: https://gitcode.com/gh_mirrors/so/source-han-serif-ttf 你是不是也经历过这种时刻:设计稿里…

2026/8/18 0:00:58 阅读更多 →
华硕笔记本控制权回收指南:GHelper 如何用一个 10MB 文件替代 Armoury Crate

华硕笔记本控制权回收指南:GHelper 如何用一个 10MB 文件替代 Armoury Crate

华硕笔记本控制权回收指南:GHelper 如何用一个 10MB 文件替代 Armoury Crate 【免费下载链接】g-helper Lightweight Armoury Crate alternative for Asus laptops with nearly the same functionality. Works with ROG Zephyrus, Flow, TUF, Strix, Scar, ProArt, …

2026/8/18 0:00:59 阅读更多 →

周新闻

基于阿里云与通义千问(Qwen)构建AI应用:从模型调用到生产部署的完整实践指南

基于阿里云与通义千问(Qwen)构建AI应用:从模型调用到生产部署的完整实践指南

如果你是一名开发者,最近可能已经感受到了AI大模型正在从“玩具”变成“生产力工具”的强烈信号。从代码补全到智能Agent,从本地部署到云端API,我们正处在一个技术栈快速重构的节点。然而,面对层出不穷的模型、框架和工具&#xf…

2026/8/17 2:58:27 阅读更多 →
工业通信系统底层逻辑:04 反射——高频能量撞墙之后会发生什么?

工业通信系统底层逻辑:04 反射——高频能量撞墙之后会发生什么?

第四篇:反射——高频能量撞墙之后会发生什么? —— 你以为信号已经过去了,其实它正在回来打你 老Q的现场笔记 第五季,我们正式进入工业神经系统层。这里不再是单个设备的战斗,而是整个工厂“经脉”层面的秩序之战。从这一篇开始,你将第一次看清:看似简单的信号传播,背…

2026/8/17 2:58:30 阅读更多 →
【文章复现】非线性值迭代自适应动态规划(ADP):离散时间非线性系统的策略迭代自适应动态规划算法研究附Matlab代码

【文章复现】非线性值迭代自适应动态规划(ADP):离散时间非线性系统的策略迭代自适应动态规划算法研究附Matlab代码

✅作者简介:热爱科研的Matlab仿真开发者,擅长毕业设计辅导、数学建模、数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。🍎 往期回顾关注个人主页:Matlab科研工作室👇 关注我领取海量matlab电子书和…

2026/8/17 2:58:32 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/17 18:54:37 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗?ncmdump解密工具帮你轻松解决这个困…

2026/8/17 18:55:16 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片:为英语学习 App 打造桌面级学习助手适用平台:HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0(API 26 Beta)新增了 AgentCard 智能体卡片能力,这是继 HMAF(鸿蒙智能体框架&#x…

2026/8/17 18:55:55 阅读更多 →