在More Setting中可以选择模板语言,在Application name中输入APP名称,如果不输入APP名称,默认新建项目不含APP,可以在建成项目后,使用命令python manage.py startapp my_app
新建APP,my_app为APP名称
下图为我新建项目的目录结构,其中discipline_inspection为图1中新建项目的项目名称,其下含有图中几个文件,其中settings为一些配置,url为路由地址,剩下两个暂时没用到。
discipline为APP,migration中存放一些数据库迁移文件,views是我新建的一个文件夹,为了方便后期编码分类,暂且不用管,urls是新建的文件,用来存放二级路由,主要用到的是models.py 和views.py,前者用来构建数据库模型,后者用来编写功能代码。
static和templates是从DattaAble项目中拷贝过来的,为了使用它的样式和模板,static存放的是静态资源。
每个类表示的是数据库中的一个表,类名即表名,上图为示例代码,charfield表示varchar字段,integerfield表示int字段,foreignkey表示外键,具体的可以查一些中文文档,此处不再赘述。
模型构建成功后,执行数据库迁移命令可以生成Django自带的sqlite3数据库,数据库迁移命令
python manage.py makemigrations
python manage.py migrate
在pycharm中安装数据库插件可以查看数据表内容,具体什么插件我忘了,百度吧。如图所示
表太长我只罗列了一部分,表中除了自己建的model还有一些系统自带的model,命名规则为app名称+model名称,auth是系统自带的用户机制,其中所有disciplineAPP下的表为自建的表
在settings.py中需要进行一些配置,其中allowed_hosts是允许访问的地址,这里测试时默认填写localhost
installed_apps中包含的是APP,其中如果是在新建时填写了APP名称,在此处不需要注册(如果注册了会报错APP重复),如果有后建的APP,需要在其后追加注册APP名称。
此处为templates的相关配置,使用Django模板需要在此处配置templates的相关信息。其中DIRS为templates文件夹的地址,此处我放在根目录下了,所以直接是basedir拼接templates文件夹名称即可。
下图为配置数据库,由于测试时使用Django默认sqlite3数据库,此处并未做改变。后期需要更换MySQL数据库时,直接在此处进行相应配置即可。
下图中,language_code是默认语言,默认为en-us英文,修改为zh-hans,timezone表示时区,这里使用Asia/Shanghai
static_url为存放一些静态资源的地址,由于templates模板需要用到一些静态资源,所以在此处需要配置静态资源地址。本项目中static文件夹存放在根目录下。
默认的urls路由配置在项目名称文件夹下,为一级路由,其中注释掉的语句为其默认的语句,这里为了方便管理一般使用二级路由,此文件中的配置作为一级路由,若项目含有多个APP,只需在此使用include的方式指向每个APP路径即可。
下图为二级路由的配置,在APP文件夹下新建urls.py文件,在该文件中编写如下格式的代码,app_name为APP名称,是为了在模板端或是在重定向时,反向解析url可以写为app:urlname格式,在后文中会提到。
在urlpatterns中配置路径,该路径分别指向的是views中方法的名称。示例代码如图,其中包含三个参数,
以首页为例,定义方法名为index,与urls中的第二个参数相对应,接收前端发送的request请求,方法中编写想要实现的功能,传递的值,最后render返回一个页面,在页面中渲染数值。render方法返回三个参数,分别是(request,url,context)url为定向的页面,context为需要向前端模板传递的json字符串。本方法主要为前端传递的是‘datalist’数据(我这里参考的一个博主的写法,和标准的写法不一样,可以百度查看render函数的具体用法。)
def index(request):
gh = request.session.get('gh')
print(gh)
if gh is None:
return redirect('discipline:login')
context = {}
datalist = []
firstlist = []
secondlist = []
thirdlist = []
title_list = []
role = client_info.objects.filter(employeeno=gh).values('roleid_id')
print(role)
functionsno = Role_function.objects.filter(role_id_id=role[0]['roleid_id'])
print(functionsno)
for no in functionsno:
fuid = model_to_dict(no)['function_id']
funo = system_function.objects.filter(id=fuid).values('function_name','functionno')
if len(funo[0]['functionno'])==1:
firstlist.append({'no':funo[0]['functionno'],'name':funo[0]['function_name']})
elif len(funo[0]['functionno'])==2:
secondlist.append({'no':funo[0]['functionno'],'name':funo[0]['function_name']})
elif len(funo[0]['functionno'])==3:
thirdlist.append({'no':funo[0]['functionno'],'name':funo[0]['function_name']})
datalist.append(fuid)
for i in firstlist:
second = []
for j in secondlist:
third = []
if j['no'][:1]==i['no']:
second.append(j['name'])
for k in thirdlist:
if k['no'][:2]==j['no']:
third.append(k['no'])
print(third)
title_list.append({'first': i['name'], 'second': second, 'third':third})
# second.clear()
context['datalist'] = title_list
context['role'] = '1'
context['first'] = firstlist
context['second'] = secondlist
context['third'] = thirdlist
print(datalist)
html_template = loader.get_template('home/index.html')
return HttpResponse(html_template.render(context, request))
其中具体涉及到的Django自带的数据库orm操作可以百度,现用现查就行,这里给一个参考链接刘江的Django教程我看的这个我觉得还挺容易理解的。
下图为Datta-Able模板的templates目录结构。
Datta-Able是使用bootstrap4的一些样式写的,下图是layouts文件夹下的base.html页面,这是整个模板的母版页之一,其余页面可以继承该页面。
下图为该页面中体中的内容,可以看出该页面中include包含了includes文件夹下的sidebar.html,sidebar是导航栏,母版页将其嵌入页面中。{% include %}是Django模板语言,可以看教程学习一些基础,其它的现用现查就行。
下图是我简单修改后的首页index.html的内容,可以看出该页面直接继承(extends)自layouts/base.html。{%block %}{%endblock %}为一个可更改的模块,在base首页中,含有block标签的地方是可更改的,想要继承父页面的导航栏,但是想自己写一些内容,就可以直接在父页面相应的block content中添加自己页面的内容。
每次新建页面的时候,直接继承base.html,在content block中编写自己需要的内容即可。
以下代码为对include/sidebar.html的修改,为了使导航栏符合我们的需求。
<nav class="pcoded-navbar">
<div class="navbar-wrapper">
<div class="navbar-brand header-logo">
<a target="_blank"
href="https://appseed.us/admin-dashboards/django-dashboard-dattaable" class="b-brand">
<div class="b-bg">
<i class="feather icon-trending-up">i>
div>
<span class="b-title">xxx工作平台span>
a>
<a class="mobile-menu" id="mobile-coll
apse" href="javascript:"><span>span>a>
div>
<div class="navbar-content scroll-div">
<ul class="nav pcoded-inner-navbar">
{% for i in datalist %}
<li class="nav-item pcoded-menu-caption">
<li class="nav-item pcoded-hasmenu">
<a href="javascript:" class="nav-link "><span class="pcoded-mtext">{{i.first}}span>a>
<ul class="pcoded-submenu">
{% for j in i.second %}
<li class="nav-item pcoded-hasmenu">
<a href="javascript:" class="nav-link "><span class="pcoded-mtext">{{j}}span>a>
li>
{% endfor %}
ul>
li>
li>
{% endfor %}
ul>
div>
div>
nav>
在登录页面中,需要提交登录用户的表单,使用form标签编写表单内容。提交方法为POST。{% csrf_token %}
该标签是Django有表单保护机制,需要在标签后添加该标签才可正常运行,但是此处不知为何我明明加了还是报错,于是采取另一种解决措施,在views中的方法前加
@csrf_exempt
标识。但是两种方式不能同时用,会报错。
{% extends "layouts/base-fullscreen.html" %}
{% block title %} Login {% endblock %}
{% block content %}
<div class="auth-wrapper">
<div class="auth-content">
<div class="auth-bg">
<span class="r">span>
<span class="r s">span>
<span class="r s">span>
<span class="r">span>
div>
<div class="card">
<div class="card-body text-center">
<div class="mb-4">
<i class="feather icon-unlock auth-icon">i>
div>
<h3 class="mb-4">
登录
h3>
<span class="mb-0 text-muted">
{{msg}}
span>
<br />
<br />
<form role="form" action="/" method="POST">
{% csrf_token %}
<div class="input-group mb-3">
<input class="form-control" name="gh" placeholder="工号">
div>
<div class="input-group mb-4">
<input type="password" class="form-control" name="pwd" placeholder="密码">
div>
<div class="form-group text-left">
<div class="checkbox checkbox-fill d-inline">
<input type="checkbox" name="checkbox-fill-1" id="checkbox-fill-a1" checked="">
<label for="checkbox-fill-a1" class="cr">保存密码label>
div>
div>
<button name="login" class="btn btn-primary shadow-2 mb-4">登录button>
form>
<p class="mb-0 text-muted">还没有账户? <a href="/register.html" >注册a>p>
<br />
div>
div>
div>
div>
{% endblock content %}
新建页面,编写模板内容,以下是index.html的示例代码。可以看到此处是继承了layout/base.html页面,我们需要做的是在首页动态渲染出侧边导航栏,导航栏是内嵌在base.html页面中,因此接参在include/sidebar.html导航栏页面中完成。
{% extends "layouts/base.html" %}
{% block title %} Dashboard {% endblock %}
{% block stylesheets %}{% endblock stylesheets %}
{% block content %}
欢迎登录xxx平台
{% endblock content %}
在8.3中展示了sidebar.html页面的代码,需要从后端获取到datalist的值,遍历datalist显示一级标题,再遍历datalist每一项的second列表,得到二级标题的名称。
可以在APP下的views中编写功能函数,向前端传递参数。在6中的index方法中,根据数据库操作查询出想获得的信息,并将其赋给context,将context通过render传给前端,返回html页面路径。