django中最常用的是使用内置的模板和admin,但是现在很流行前后端分离的开发方式,后端程序只提供RESTFUL接口,前端程序绘制页面交互, 相比之下,基于模板的开发方式就显得不那么灵活,而且有一定的学习成本。
如果在django模板直接引用vue.js的方式进行开发,还要考虑到模板标签的冲突问题,要么更换vue模板标签,要么使用特定标签verbatim进行处理,保证django模板能够正确的区分django 的标签和vue的标签,但是开发人员仍然要注意两种模板的语法区别。
... <div id="app"> {{ django_var }} {% verbatim vueblock %} ... <div class="title">{{ vue_var }}</div> ... <script src=".../vue.js"></script> <script> new Vue({ el: '#app', data: { vue_var: 'this is a test', }, ... }) </script> {% endverbatim vueblock%} </div>
如果采用前后端分离的开发方式,最彻底的方式就是抛弃掉django admin,完全重写后端接口和前端页面,那么工作量会增加很多,还要单独熟悉 django auth的业务逻辑和表结构。 既然不用django admin了,那也可以不用django了, 不如换成 FastAPI,flask写后端接口吧…
话说回来,正好有一个使用django开发的预约管理系统,包含了字典,设置,会员,排班预约等很多功能页面。其中预约页面是以列表形式展现的,不够直观,业务部门期望能够以日历的形式更直观的展示

经过评估,django开发认为,可以自定义changelist.html模板,但在页面中使用vue工作量比较大。vue不太熟悉django模板,需要学习。最终方案,创建一个vue单页面项目, 后端使用django提供页面的接口,在django admin的菜单中挂前端页面的链接。
这里说一下,实现的方式,在预约项目的根目录创建一个前端页面目录web,dist目录是我的前端构建产物。router/index.js是 vue的路由代码

在django的settings.py中,修改模板配置,使其包含 web/dist目录
TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': ['templates', os.path.join(BASE_DIR, 'web/dist')], 'APP_DIRS': True, ... } ]
配置好模板后,还要管理静态资源文件,在settings.py中还要配置静态资源目录,使其包含 web/dist
STATICFILES_DIRS = [ os.path.join(BASE_DIR, "web/dist") ]
在django的主urls.py中,增加一行配置,为了让django能够托管vue的页面
urlpatterns = [ ... path('web/', TemplateView.as_view(template_name='index.html')), ]
以上配置完成后, 使用 npm run build之类的命令对前端项目打包后,就会生成dist目录, 再启动django程序,就能用整合好的地址访问页面了: http://127.0.0.1:8000/web/#/
下一步, 把django admin的菜单地址替换掉,还要考虑潜在的传参数的问题,那就加一个模板处理,在templates目录下创建一个模板文件 appointlist/redirect.html,内容如下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> </head> <body> <script> window.location.href = '/web/#/?userid={{userid}}¶m2={{param2}}' </script> </body> </html>
然后,在admin.py中的管理类中,修改 change_list_template属性,指向刚定义的模板
@admin.register(ReservationList) class ReservationGridAdmin(ModelAdmin): change_list_template = 'book_reservation/reserve.html' def changelist_view(self, request, extra_context=None): userid = request.user.id param2 = 'this is a spreadsheet' extra_context = {'userid': userid, 'param2': param2} return super().changelist_view(request, extra_context)
再重新运行django程序看效果

总结一下,不改变整体django程序的情况下,个别页面使用vue单页面方式进行开发是可行的,完美的融入到django的菜单体系中,需要在django中做一些相应的配置,单独实现页面所需的接口, 前端开发不需要更多的时间学习新的模板语法,更不需要考虑在django模板中使用其他语法带来的工作量提升。
2025/9/14 于 北京 上东廓