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 于 北京 上东廓