Web_Fast_Development

本文最后更新于:4 个月前

网页开发

1.快速开发网站

1.1初试Flask

返回字符串

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from flask import Flask

# 创建app实例
app = Flask(__name__)


# 创建路由网址与函数index的关系
@app.route("/info")
def index():
return "我的开发从这里开始"


if __name__ == '__main__':
app.run()

返回一个html网页

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from flask import Flask,render_template

# 创建app实例
app = Flask(__name__)


# 创建路由网址与函数index的关系
@app.route("/info")
def info():
#默认打开该目录下的templats目录下的index.html文件
return render_template("./index.html")


if __name__ == '__main__':
app.run()

2.浏览器能识别的标签

2.1编码(head)

1
<meta charset="UTF-8">

2.2title(head)

1
<title>LoveStory</title>

2.3标题(body)

1
2
3
4
5
6
<h1>一级标题</h1>
<h2>二级标题</h2>
<h3>三级标题</h3>
<h4>四级标题</h4>
<h5>五级标题</h5>
<h6>六级标题</h6>

2.4div和span(body)

1
2
<div>块级标签</div>
<span>行内标签/内联标签</span>
  • div独占一行,块级标签
  • span有多大占多大,行内标签也叫内联标签

div和span样式由CSS渲染设定。

2.5超链接(body)

1
2
3
4
<!--当前页面绝对跳转到完整网址-->
<a href="https://fcsy.fit">绝对跳转</a>
<!--新建页面绝对跳转到完整网址-->
<a href="https://fcsy.fit" target="_blank">绝对跳转</a>
1
2
<!--相对跳转到本地其他目录-->
<a href="/time">相对跳转</a>
1
2
<!--相对跳转到本地其他目录-->
<a href="#">空跳转</a>

绝对跳转

2.6图片(body)

可以写内嵌式css,eg:style="height:100px",以分号(;)隔开

1
2
<!--网络图片绝对地址-->
<img src="https://t7.baidu.com/it/u=1819248061,230866778&fm=193&f=GIF" style="height:100px"/>
1
2
<!--本地图片相对地址,flask要求本地图片必须存放在static目录下-->
<img src="/static/picture.png"/>

shadow-随便写

2.7音频(body)

1
2
3
4
<center>
<audio src="https://lo-sycdn.kuwo.cn/3f7fd58e7bca702aa2835729bbde7e1d/63764e76/resource/n1/62/42/3385123058.mp3" controls="" preload="metadata">暂时无法播放
</audio>
</center>

外联音频播放器

2.8视频(body)

1
2
3
4
<center>
<video src="https://vd4.bdstatic.com/mda-mkm388zceiim43xq/540p/h264_cae/1637547444425365643/mda-mkm388zceiim43xq.mp4">
</video>
</center>

外链视频播放器

1
2
3
4
<div style="position: relative; padding: 30% 45%;">
<iframe style="position: absolute; width: 100%; height: 100%; left: 0; top: 0;" src="视频地址去B站分享按钮下iframe里面的src属性值复制" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true">
</iframe>
</div>

2.9列表(body)

  1. 无序列表

    1
    2
    3
    4
    5
    <ul>
    <li>中国移动</li>
    <li>中国电信</li>
    <li>中国联通</li>
    </ul>
    • 中国移动
    • 中国电信
    • 中国联通
  2. 有序列表

    1
    2
    3
    4
    5
    <ol>
    <li>中国移动</li>
    <li>中国电信</li>
    <li>中国联通</li>
    </ol>
    1. 中国移动
    2. 中国电信
    3. 中国联通

2.10表格(body)

1
2
3
4
5
6
7
8
9
10
<table>
<thead>
<tr> <th>ID</th> <th>姓名</th> <th>年龄</th> </tr> //表头
</thead>
<tbody>
<tr> <td>1</td> <td>Alleyf</td> <td>20</td> </tr> //表格内容
<tr> <td>1</td> <td>Alleyf</td> <td>20</td> </tr>
<tr> <td>1</td> <td>Alleyf</td> <td>20</td> </tr>
</tbody>
</table>
ID 姓名 年龄
1 Alleyf 20
2 ChuiYuGin 20
3 Alleyf 15
`案例`
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
<table border="1">
<thead>
<tr>
<th>ID</th>
<th>头像</th>
<th>姓名</th>
<th>邮箱</th>
<th>更多信息</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>
<img src="static/images/01.webp" alt="" class="hp">
</td>
<td>alleyf</td>
<td>alleyf@gmail.com</td>
<td>
<a href="https://fcsy.fit" target="_blank">更多信息</a>
</td>
<td>编辑 删除</td>

</tr>
<tr>
<td>2</td>
<td>
<img src="static/images/02.webp" alt="" class="hp">
</td>
<td>chuiyugin</td>
<td>chuiyugin@gmail.com</td>
<td>
<a href="https://chuiyugin.github.io" target="_blank">更多信息</a>
</td>
<td>编辑 删除</td>
</tr>
<tr>
<td>2</td>
<td>
<img src="static/images/03.webp" alt="" class="hp">
</td>
<td>chuiyugin</td>
<td>chuiyugin@gmail.com</td>
<td>
<a href="https://chuiyugin.github.io" target="_blank">更多信息</a>
</td>
<td>编辑 删除</td>
</tr>
<tr>
<td>2</td>
<td>
<img src="static/images/04.webp" alt="" class="hp">
</td>
<td>chuiyugin</td>
<td>chuiyugin@gmail.com</td>
<td>
<a href="https://chuiyugin.github.io" target="_blank">更多信息</a>
</td>
<td>编辑 删除</td>
</tr>

</tbody>
</table>

2.11表单(body)

  1. input系列(7个)

    1
    2
    3
    4
    5
    6
    7
    8
       <input type="text">
    <input type="password">
    <input type="file"></input>
    单选 <input type="radio" name="gender" checked=""></input>
    复选 <input type="checkbox">篮球</input>
    <input type="button" value="登录">
    <input type="submit" value="提交">

  2. 下拉框系列(2个)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    单选下拉框
    <select>
    <option>金钱</option>
    <option>美人</option>
    <option>地位</option>
    <option>名声</option>
    <option>归隐</option>
    </select>
    多选下拉框
    <select multiple>
    <option>金钱</option>
    <option>美人</option>
    <option>地位</option>
    <option>名声</option>
    <option>归隐</option>
    </select>
  3. 多行输入

    1
    <textarea cols="10" rows="5">默认输入</textarea>

    实例

用户名:
密码:
性别:
爱好:篮球 IT 游戏
城市:
特长:
备注:

小结

  • 划分

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    -块级标签
    <h1></h1>
    <p></p>
    <div></div>
    <ul></ul>
    <ol></ol>
    <table></table>
    -行内标签
    <span></span>
    <a href=""></a>
    <img src=""/>
    <audio></audio>
    <video></video>
  • 嵌套

    1
    2
    3
    4
    5
    6
    -点击图片跳转网页
    <p align="center">
    <a href="https://fcsy.fit target="_blank">
    <img src=""/>
    </a>
    </p>

综合案例–登录注册

  • 导入flask,创建app

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    '''
    Author: Alleyf 3035581811@qq.com
    Github: https://github.com/Alleyf
    QQ: 3035581811
    Signature: You know more,you know less
    Date: 2022-11-19 20:57:35
    LastEditors: Alleyf 3035581811@qq.com
    LastEditTime: 2022-11-20 10:43:50
    FilePath: \login_register\app.py
    Copyright (c) 2022 by Alleyf 3035581811@qq.com, All Rights Reserved.
    '''
    from flask import Flask, render_template, request, jsonify

    app = Flask(__name__)

    根据method的不同分别处理
    @app.route('/register', methods=["GET", "POST"])
    def register():
    if request.method == "GET":
    return render_template('register.html')
    else:
    user = request.form.get("username")
    pwd = request.form.get("password")
    gender = request.form.get("gender")
    hobbies = request.form.getlist("hobby")
    city = request.form.get("city")
    characters = request.form.getlist("characters")
    notes = request.form.get("notes")
    print(user, pwd, gender, hobbies, city, characters, notes)
    info = {
    "user": user,
    "pwd": pwd,
    "gender": gender,
    "hobbies": hobbies,
    "city": city,
    "characters": characters,
    "notes": notes
    }
    return render_template('login.html')
    # return jsonify(info)


    @app.route('/user/<username>', methods=["GET", "POST"])
    def userdemo(username):
    return f'Hello {username}!'

    if __name__ == '__main__':
    app.run()
  • HTML实现注册

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    <!DOCTYPE html>
    <html lang="en">

    <head>
    <meta charset="UTF-8">
    <title>Register</title>
    <!-- <link rel="stylesheet" type="text/css" href="static/css/register.css" /> -->
    <style>
    * {
    padding: 0;
    margin: 0;
    }

    html {
    height: 100%;
    }

    body {
    background-image: linear-gradient(to bottom right, rgb(114, 135, 254), rgb(130, 88, 186));
    }



    </style>
    </head>

    <body>
    <center>
    <h1>用户注册</h1>
    <form method="post" action="/register">
    <div>
    用户名:<input type="text" name="username">
    </div>
    <div>
    密码:<input type="password" name="password">
    </div>
    <div>
    性别:
    <input type="radio" name="gender" value="1">
    <input type="radio" name="gender" value="2">
    </div>
    <div>
    爱好:
    <input type="checkbox" name="hobby" value="10">篮球
    <input type="checkbox" name="hobby" value="20">足球
    <input type="checkbox" name="hobby" value="30">排球
    <input type="checkbox" name="hobby" value="40">乒乓球
    </div>
    <div>
    城市:
    <select name="city">
    <option value="bj">北京</option>
    <option value="sh">上海</option>
    <option value="gz">广州</option>
    <option value="xa">西安</option>
    </select>
    </div>
    <div>
    特长:
    <select name="characters" multiple>
    <option value="100">java</option>
    <option value="101">c++</option>
    <option value="102">python</option>
    <option value="103">Go</option>
    </select>
    </div>
    <div>
    备注:<textarea name="notes" cols="50" rows="5"></textarea>
    </div>

    <div>
    <!-- 普通按钮-->
    <input type="submit" value="注册">
    <!-- 提交表单数据到指定地址-->
    <input type="button" value="注册">
    </div>
    </form>

    <!-- <iframe frameborder="no" border="0" marginwidth="0" marginheight="0" width=330 height=86-->
    <!-- src="//music.163.com/outchain/player?type=2&id=475479888&auto=1&height=66"></iframe>-->

    </center>
    <script type="text/javascript">
    window.onload = function (){
    let mycenter = document.createElement('center');
    let myiframe = document.createElement('iframe');
    myiframe.setAttribute('src','//music.163.com/outchain/player?type=2&id=475479888&auto=1&height=66');
    myiframe.setAttribute('style','frameborder:no; border:0; marginwidth:0; marginheight:0; width:400; height:86')
    //把div添加到body作为他的子元素
    mycenter.appendChild(myiframe);
    document.body.appendChild(mycenter);
    }


    </script>

    </body>

    </html>
  • 提交数据到后台

    1
    <form method="post" action="/register">
  • 流程展示

  1. form标签包裹要提交的数据的标签
    • 提交方式:method="get"
    • 提交地址:action="/xxx/xxx/xxx"
    • 在form标签里面必须有一个submit标签
  2. 在form里面的一些标签:input/select/textarea
  • 一定要写**name**属性

  • 后台处理数据

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    @app.route('/register', methods=["GET", "POST"])
    def register():
    if request.method == "GET":
    return render_template('register.html')
    else:
    user = request.form.get("username")
    pwd = request.form.get("password")
    gender = request.form.get("gender")
    hobbies = request.form.getlist("hobby")
    city = request.form.get("city")
    characters = request.form.getlist("characters")
    notes = request.form.get("notes")
    print(user, pwd, gender, hobbies, city, characters, notes)
    return render_template('login.html')
1
2
3
4
5
6
7
8
9
10
>from flask import jsonify
>... ...
>@app.route('/json_return')
>def json_return():
j = {
"name":"北京图灵学院",
"teacher":"刘大拿",
"Blog_address":"http://www.mycode.wang"
}
return jsonify(j)

接受post请求返回json字符串

3.CSS样式

css是美化html内容的层叠样式表

3.1快速了解

1
2
3
<img src="```" style="height:100px;width:200px"/>
<div style="color:blue;"> CSS
</div>

3.2CSS引用方式

1.行内式

1
2
3
4
5
6
7
<body style="background-color:black;">

<h1 style="color:white;padding:30px;">Hostinger Tutorials</h1>

<p style="color:white;">Something usefull here.</p>

</body>
  • 行内样式表(内联样式表)是在元素标签内部的style属性中设定CSS样式。适合于修改简单样式.
  • style实就是标签的属性
  • 在双引号中间,写法要符合CSS规范
  • 可以控制当前的标签设置样式

2.内嵌式

1
2
3
4
5
6
7
8
9
10
11
12
13
<head>

<style type="text/css">

p {color:white; font-size: 10px;}

.center {display: block; margin: 0 auto;}

#button-go, #button-back {border: solid 1px black;}

</style>

</head>
  • 标签理论上可以放在HTML文档的任何地方,但一般会放在文档的标签中

  • 通过此种方式,可以防便控制当前整个页面中的元素样式设置

  • 代码结构清晰,但是并没有实现结构与样式完全分离

3.外联式

1
2
3
4
5
<head>

<link rel="stylesheet" type="text/css" href="style.css" />

</head>

3.3CSS选择器

作用: 选择标签设置格式属性

选择器分为基础选择器和复合选择器两个大类,我们这里先讲解一下基础选择器。

  • 基础选择器是由单个选择器组成的
  • 基础选择器包括:标签选择器、类选择器、id 选择器和通配符选择器

3.3.1标签选择器

标签选择器(元素选择器)是指用HTML标签名称作为选择器,按标签名称分类,为页面中某一类标签指定统一的CSS样式。

语法:

1
2
3
4
5
标签名 {
属性1: 属性值1;
属性2: 属性值2;
属性3 属性值3; ···
}

3.3.2类选择器

如果想要差异化选择不同的标签,单独选一个或者某几个标签 ,可以使用类选择器;样式点定义,结构类调用,一个或多个,开发最常用

语法:

1
2
3
4
5
.类名 {
属性1:属性值1;
···
}
<p class="p1">CSS</p>

多类名语法:

<div class="name1 name2 ···"></div>

  • 在标签class属性中写多个类名,可以同时被调用
  • 多个类名中间必须用空格分开
  • 将相同样式放在一个公共样式里,便于调用,提高代码复用率

3.3.3ID选择器

  • id选择器可以为标有特定id的HTML元素指定特定的样式。
  • HTML元素以id属性来设置id选择器, CSS中id选择器以“#” 来定义
  • id标签格式只能被调用一次,唯一性(常与js使用)

语法:

1
2
3
4
5
#ID名 {
属性1:属性值1;
···
}
<p id="p1">CSS</p>

3.3.4通配符选择器

  • 在CSS中,通配符选择器使用*定义,它表示选取页面中所有元素(标签)。
  • 标签不需要主动调用,自动会给所有元素设置该格式
  • 特殊情况才使用,后面讲解使用场景(以下是清除所有的元素标签的内外边距)

语法:

1
2
3
4
* {
margin0
padding0
}

3.3.5属性选择器

  • 在CSS中给类选择器**添加属性修饰**以设置该属性的标签的样式

语法:

1
2
3
.类名[name="user"] {
color: pink;
}

3.3.6子代选择器

  • 在CSS中给类选择器**添加子类**单独设置子类的样式

语法:

所有子代

1
2
3
.类名 子类名/子标签 {
color: pink;
}

直接子代

1
2
3
.类名 > 子类名/子标签 {
color: pink;
}

3.3.7多个和覆盖

不同样式则共同起作用,相同样式则后者覆盖前者,前后由CSS写的顺序决定。

重复的样式要想不被后者覆盖需要在样式后面加!important关键词

1
2
3
4
5
6
7
8
9
<style>
.c1{
color: red !important;
border: 1px solid red;
}
.c2{
font-size: 28px;
color: blue;
}

此时c2的颜色不会覆盖c1的颜色。

3.3.8常用选择器

类选择器,标签选择器,后代选择器

3.4样式

1.高度和宽度

1
2
3
4
.c1{
height: 300px;
width: 500px/50%;
}
  • 宽度支持百分比,因为一个网页总宽度是固定,但高度不固定。
  • 行内标签:默认无效
  • 块级标签:默认有效(霸道,右侧区域空白,不给占用)

2.块级和行内标签

让标签既具有行内标签的特点也具有块级标签的特点

1.CSS样式:标签->display:inline-block;

1
2
3
.number {
display: inline-block;
}

2.块级和行内转换:

块级转行内标签->display:inline;

行内转块级标签->display:block;

1
2
3
4
5
6
.number {
display: inline;
}
.pwd {
display: block;
}

注意:块级+块级&行内用的多

3.字体设置

  • 颜色

  • 大小

  • 加粗

  • 字体格式

1
2
3
4
5
6
.number{
color: #rgb/red;
font-size: 28px;
font-weight: 600;
font-family: Microsoft Yahei;
}

4.文字对齐方式

1
2
3
4
5
6
7
8
9
.slogan {
display: inline-block;
height: 59px;
width: 500px;
color: cornflowerblue;
border: 1px solid blue;
text-align: center;/*水平居中*/
line-height: 59px;/*垂直居中*/
}

5.浮动

设置标签在一行中的不同位置

1
2
<span>上一页</span>
<span style="float: right;">下一页</span>

块级标签设置float属性后宽度高度可变

浮动的标签脱离了文档流(飘起来了),需要用style="clear:both;"恢复正常

1
2
3
4
5
6
7
<div style="background-color: aquamarine">
<div>
<button class="b" style="float: left;">上一页</button>
<button class="b" style="float: right;">下一页</button>
<div style="clear: both"></div>/*如果没有这句父div将看不到背景颜色*/
</div>
</div>

6.内边距

标签内部设置指定像素的距离

1
2
3
4
.note {
padding: 20px;/*设置全部方向内边距为20px*/
/*padding: 20px 10px 5px 10px;分别设置上右下左顺时针方向的内边距*/
}

7.外边距

设置本标签与别的标签之间的距离(会增加原来的高度)

1
2
3
4
.note {
margin: 20px;/*设置全部方向外边距为20px*/
/*margin: 20px 10px 5px 10px;分别设置上右下左顺时针方向的外边距*/
}

8.hover(伪类)

hover不但可以在鼠标悬浮在该标签上设置自己的样式还可以设置它的子标签的样式

设置自己样式:

1
2
3
4
.slider .news .container img:hover {
box-shadow: 0 16px 32px 0 rgba(48, 55, 66, 0.15); /* 鼠标悬浮时盒子出现的阴影 */
transform: translate(0, -10px); /* 鼠标悬浮时盒子上移10px */
}

设置子类样式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
.app {
height: 100px;
width: 100px;
margin: 0 auto;
}

.qcode {
display: none;
width: 50px;
margin: 0 auto;
}

.app:hover .title {
color: red;
}

.app:hover .qcode {
display: block;
}

9.after(伪类)

在标签内容尾部追加内容

1
2
3
 .title:after {
content: "nishizhu";
}

可以清除浮动样式

1
2
3
4
5
6
7
8
9
10
11
12
13
       .clearfix .item {
float: left;
}
.clearfix:after {
content: "";
display: block;
clear: both;
}
<div class="clearfix">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
</div>

10.position

  • fixed
  • relative
  • absolute
  1. fixed:固定在窗口的某个位置。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    .back {
    position: fixed;
    width: 70px;
    height: 50px;
    /*border: 1px solid red;*/
    right: 15px;
    bottom: 50px;
    line-height: 50px;
    text-align: center;
    }

案例:对话框

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/*幕布*/
.mask {
position: fixed;
background-color: black;
top: 0;
bottom: 0;
right: 0;
left: 0;
opacity: 0.7;
z-index: 999;
/*display: none;*/
}
.dialog {
position: fixed;
width: 500px;
height: 300px;
background-color: darkseagreen;
left: 0;
right: 0;
top: 200px;
margin: 0 auto;
z-index: 1000;
/*display: none;*/
}
  1. relative和absolute:设置相对和绝对位置,一般设置父类为relative子类为absolute,对子类进行布局。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    .parent {
    position: relative;
    width: 500px;
    height: 300px;
    }
    .son {
    position: absolute;
    width: 100px;
    height: 100px;
    right: 0;/*布局在父类的右上方*/
    top: 0;
    }

案例:小米商城下载app

1
2
3
4
5
6
<a href="#" class="app">下载app
<div class="qcode">
<img src="/static/imgs/公众号.jpg" style="width: 100px;" alt="">
</div>
<div style="clear: both"></div>
</a>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
.app {
width: 100px;
margin: 0 auto;
position: relative;
}

.qcode {
display: none;
width: 50px;
margin: 0 auto;
position: absolute;
right: 50%;
float: bottom;
}

.app:hover .qcode {
display: block;
}

11.border(边框)

1
2
3
4
5
6
7
8
9
10
.bor {
border: 3px solid transparent;
background-color: gold;
width: 500px;
height: 500px;
margin: 0 auto;
}
.bor:hover {
border: 1px solid red;
}

12.背景色

设置标签背景色

1
2
3
.c1 {
background-color: red/#fff/rgb(255,255,255);
}

4.案例:小米商城

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>小米商城</title>
<link rel="stylesheet" href="/static/css/home.css">
</head>
<body>
<div class="header">
<div class="container">
<div class="menu">
<a href="#">小米官网</a>
<a href="#">小米商城</a>
<a href="#">MIUI</a>
<a href="#">IOT</a>
<a href="#">云服务</a>
<a href="#">天星数科</a>
<a href="#">有品</a>
<a href="#">小爱开放平台</a>
<a href="#">企业团购</a>
<a href="#">资质证照</a>
<a href="#">协议规则</a>
<a href="#">下载app</a>
<a href="#">Select Location</a>
</div>
<div class="account">
<a href="#">登录</a>
<a href="#">注册</a>
<a href="#">消息通知</a>
</div>

<div>
<a href="#">
<em class="iconfont-cart"></em>
购物车
<span class="cart-mini-num J_cartNum">(0)</span>
</a>
</div>
<div style="clear: both"></div>

</div>
</div>
</body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
body {
margin: 0;
}

.header {
position: relative;
/*height: 40px;*/
color: #b0b0b0;
background: #333;
}

.container {
width: 1226px;
margin: 0 auto;
}

.header a {
color: #b0b0b0;
line-height: 40px;
font-size: 12px;
display: inline-block;
margin-right: 10px;
}

.container .menu {
float: left;
}

.container .account {
float: right;
}

总结

  • body标签,默认有一个边距,造成页面四边都有白色间隙,如何去除呢?

    1
    2
    3
    body {
    margin0
    }
  • 内容垂直居中

    • 文本居中

      1
      2
      3
      4
      .container {
      line-height: 100px;
      text-align:center;
      }
    • 其他内容居中

      1
      2
      3
      .container {
      margin-top: 22px;/*设置内容的外边距(内容不能是行内标签,行内标签无法设置宽高和边距,可以转为inline-block)*/
      }
  • 内容水平居中

    • 文本居中,文本会在这个区域中居中。

      1
      <div style="width: 200px; text-align: center; line-height:10px">文本居中</div>
    • 区域居中,自己要有宽度+margin-left:auto;margin-right:auto;

      1
      2
      3
      4
      .container {
      width:980px;
      margin: auto;
      }
    • 父亲没有高度或宽度,会被孩子撑起来。

    • 如果存在浮动,一定记得加入。

      image-20221122213543681

    • 如果想要用别人的样式,用浏览器开发者工具分析别人样式。

    • a标签默认有下划线,用style="text-decoration:none;"去除

    • 鼠标放上去改变标签样式用hover来设置

      1
      2
      3
      .c1:hover{
      color: red;
      }
    • 设置透明度opacity

      1
      2
      3
      .c1 {
      opacity: 0.7;
      }

4.Bootstrap

1.下载引用

1
2
3
4
5
    {#    开发版未压缩#}
<link rel="stylesheet" href="/static/plugins/bootstrap-5.2.3/css/bootstrap.css">
{# 生产版已压缩#}
{# <link rel="stylesheet" href="/static/plugins/bootstrap-5.2.3/css/bootstrap.min.css">#}
<script src="/static/plugins/bootstrap-5.2.3/js/bootstrap.js"></script>

2.导航

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!-- Nav pills -->
<ul class="nav nav-pills">
<li class="nav-item">
<a class="nav-link active" data-bs-toggle="pill" href="#home">首页</a>
</li>
<li class="nav-item">
<a class="nav-link" data-bs-toggle="pill" href="#about">关于</a>
</li>
<li class="nav-item">
<a class="nav-link" data-bs-toggle="pill" href="#links">链接</a>
</li>
</ul>

<!-- Tab panes -->
<div class="tab-content">
<div class="tab-pane active container" id="home">首页</div>
<div class="tab-pane container" id="about">关于</div>
<div class="tab-pane container" id="links">链接</div>
</div>

3.栅格

  • 把一行划分为12格

  • 分类

    1. 响应式:根据页面宽度不同动态变化

      1
      2
      3
      .col-sm- 1170px 常用
      .col-md- 970px
      .col-lg- 750px
    2. 非响应式:不随页面大小变化,固定水平排列

      1
      2
      3
      4
      5
      6
      7
      8
      9
      .col-xs-
      <div class="container">
      <div class="row">
      <div class="col-sm-6" style="height: 40px;background: black">
      <input type="button" class="btn btn-primary" value="tijiao">
      </div>
      <div class="col-sm-6" style="height: 40px;background: red"></div>
      </div>
      </div>
    3. 列偏移

      1
      <div class="col-sm-offset-2 col-sm-6" style="height: 40px;background: gold"></div>列偏移两个栅格col

4.container

  •     <div class="tab-pane active container" id="home">居中
            <div class="container row">
                <div class="col-sm-9" style="background: red; height: 700px">
    
                </div>
                <div class="col-sm-3" style="background: green;height: 700px"></div>
            </div>
        </div>
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10

    ```html
    <div class="tab-pane active container" id="home">
    <div class="container-fluid row">
    <div class="col-sm-9" style="background: red; height: 700px">

    </div>
    <div class="col-sm-3" style="background: green;height: 700px"></div>
    </div>
    </div>

5.面板

默认不带标题和带标题的面板

image-20221125221650667

默认示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
不带标题
<div class="panel panel-default">
<div class="panel-heading">Panel heading without title</div>
<div class="panel-body">
Panel content
</div>
</div>
带标题
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">Panel title</h3>
</div>
<div class="panel-body">
Panel content
</div>
</div>

不同风格的面板

image-20221125221417847

风格设置:

1
2
3
4
5
<div class="panel panel-primary">...</div>
<div class="panel panel-success">...</div>
<div class="panel panel-info">...</div>
<div class="panel panel-warning">...</div>
<div class="panel panel-danger">...</div>

面板示例:

1
2
3
4
5
6
7
8
<div class="panel panel-success">
<div class="panel-heading" style="background: #d6e9c6">
<h3 class="panel-title">Panel title</h3>
</div>
<div class="panel-body">
Panel content
</div>
</div>

案例:登录

要点:

  • 宽度+居中(区域)

  • 内边距

  • 表单

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    <!--
    ~ Copyright (c) 2022. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
    ~ Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan.
    ~ Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna.
    ~ Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus.
    ~ Vestibulum commodo. Ut rhoncus gravida arcu.
    -->

    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>Login</title>
    <link rel="stylesheet" href="/static/plugins/bootstrap-3.4.1/css/bootstrap.css">
    <link rel="stylesheet" href="/static/plugins/bootstrap-3.4.1/js/bootstrap.js">
    <link rel="stylesheet" href="/static/css/login.css">
    </head>
    <body>
    <div class="container-fluid">
    <div class="login">
    <h3 class="h3 text-center">用户登录</h3>
    <div class="input-group">
    <p>用户名或手机号</p>
    <input type="text" class="form-control" placeholder="Username" aria-describedby="basic-addon1">
    </div>

    <div class="input-group">
    <p>密码</p>
    <input type="password" class="form-control" placeholder="password" aria-describedby="basic-addon2">
    </div>

    <div class="input-group">
    <p>图片验证码</p>
    <input type="text" class="form-control"
    placeholder="verify code" aria-label="Amount (to the nearest dollar)">
    </div>

    <div class="input-group">
    <input type="submit" class="form-control btn btn-primary" id="basic-url" aria-describedby="basic-addon3"
    value="登录"
    onclick="">
    </div>
    </div>
    </div>
    </body>
    </html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
/*
* Copyright (c) 2022. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
* Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan.
* Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna.
* Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus.
* Vestibulum commodo. Ut rhoncus gravida arcu.
*/
.container-fluid {
margin: 0;
background: linear-gradient(#cdcee7, lightcyan);
}

.login {
/*float: left;*/
/*display: inline-block;*/
/*height: 200px;*/
box-shadow: 4px 4px 20px #abc;
width: 350px;
margin: 80px auto;
padding: 20px 40px;
position: relative;
border: 1px solid transparent;
border-radius: 5px;
/*text-align: center;*/
}

.login:hover {
/*border: 1px solid;*/
background: linear-gradient(#b49fcc, #b0b0f3);
color: white;
}

.login div {
/*display: inline-block;*/
/*height: 20px;*/
/*width: 200px;*/
margin: 2px auto;
/*position: absolute;*/
/*right: 50%;*/
}

.login .input-group {
border-radius: 10px;
}

6.表单

1
2
3
4
<div class="input-group">
<p>用户名或手机号</p>
<input type="text" class="form-control" placeholder="Username" aria-describedby="basic-addon1">
</div>

7.表格

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
<div class="tablelist text-center">
<table class="table table-hover table-bordered">
<thead>
<tr>
<th>#</th>
<th>First Name</th>
<th>Last Name</th>
<th>Username</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">1</th>
<td>Mark</td>
<td>Otto</td>
<td>@mdo</td>
<td>
<a href="">
<button class="btn btn-primary btn-xs">编辑</button>
<button class="btn btn-danger btn-xs">删除</button>
</a>
</td>
</tr>
<tr>
<th scope="row">2</th>
<td>Jacob</td>
<td>Thornton</td>
<td>@fat</td>
<td>
<a href="">
<button class="btn btn-primary btn-xs">编辑</button>
<button class="btn btn-danger btn-xs">删除</button>
</a>
</td>
</tr>
<tr>
<th scope="row">3</th>
<td>Larry</td>
<td>the Bird</td>
<td>@twitter</td>
<td>
<a href="">
<button class="btn btn-primary btn-xs">编辑</button>
<button class="btn btn-danger btn-xs">删除</button>
</a>
</td>
</tr>
</tbody>
</table>
</div>

案例:后台管理

要求:

  • 导航

  • 新建,按钮

  • 表格

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Title</title>
    <link rel="stylesheet" href="/static/plugins/bootstrap-3.4.1/css/bootstrap.css">
    <link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css">
    <link rel="stylesheet" href="/static/plugins/bootstrap-3.4.1/js/bootstrap.js">
    <link rel="stylesheet" href="/static/css/adminsystem.css">

    </head>
    <body>
    <nav class="navbar navbar-default">
    <div class="container">
    <!-- Brand and toggle get grouped for better mobile display -->
    <div class="navbar-header">
    <button type="button" class="navbar-toggle collapsed" data-toggle="collapse"
    data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
    <span class="sr-only">Toggle navigation</span>
    <span class="icon-bar"></span>
    <span class="icon-bar"></span>
    <span class="icon-bar"></span>
    </button>
    <a class="navbar-brand" href="#">医学文献管理系统</a>
    </div>

    <!-- Collect the nav links, forms, and other content for toggling -->
    <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
    <ul class="nav navbar-nav">
    <li class="active"><a href="#"><span class="glyphicon glyphicon-folder-open" aria-hidden="true"></span>文档目录
    <span class="sr-only">(current)</span></a></li>
    <li><a href="#"> <span class="glyphicon glyphicon-user" aria-hidden="true"></span>
    用户管理</a></li>
    <li><a href="#"><span class="glyphicon glyphicon-cloud" aria-hidden="true"></span> 数据可视化</a></li>

    </ul>
    <form class="navbar-form navbar-left">
    <div class="form-group">
    <input type="text" class="form-control" placeholder="Search">
    </div>
    <button type="submit" class="btn btn-default">搜索</button>
    </form>
    <ul class="nav navbar-nav navbar-right">
    <li><a href="#">登录</a></li>
    <li><a href="#">注册</a></li>
    </ul>
    </div><!-- /.navbar-collapse -->
    </div><!-- /.container-fluid -->
    </nav>
    <div class="container">
    <div class="panel panel-default">
    <div class="panel-heading">
    <span class="glyphicon glyphicon-pencil" aria-hidden="true"></span>
    录入文献
    </div>
    <div class="panel-body">
    <form>
    <div class="form-group">
    <label for="exampleInputEmail1">上传人</label>
    <input type="email" class="form-control" id="exampleInputEmail1" placeholder="submit-person">
    </div>
    <div class="form-group">
    <label for="exampleInputPassword1">重要指数</label>
    <input type="text" class="form-control" id="exampleInputPassword1"
    placeholder="importance-index">
    <p class="help-block">重要指数区间为(0.0, 1.0)</p>
    </div>
    <div class="form-group">
    <label for="exampleInputFile">File input</label>
    <input type="file" class="" id="exampleInputFile">
    <p class="help-block">请选择您要导入的医学文献!</p>
    </div>
    <button type="submit" class="btn btn-success">提交</button>
    </form>
    </div>
    </div>

    </div>

    <div class="container">
    <div class="btnlist" style="margin-bottom: 20px">
    <button type="button" value="" class="btn btn-info">新建</button>
    <button type="button" value="" class="btn btn-info">编辑</button>
    <button type="button" value="" class="btn btn-info">删除</button>
    <button type="button" value="" class="btn btn-info">导入</button>
    </div>
    <div class="panel panel-default">
    <div class="panel-heading">
    <h3 class="panel-title">
    <span class="glyphicon glyphicon-th-list"></span> 文献速览</h3>
    </div>
    <div class="panel-body">
    注意:您可以对下面的文献进行人性化管理。
    </div>
    <div class="tablelist text-center">
    <table class="table table-hover table-bordered">
    <thead>
    <tr>
    <th>#</th>
    <th>First Name</th>
    <th>Last Name</th>
    <th>Username</th>
    <th>Action</th>
    </tr>
    </thead>
    <tbody>
    <tr>
    <th scope="row">1</th>
    <td>Mark</td>
    <td>Otto</td>
    <td>@mdo</td>
    <td>
    <a href="">
    <button class="btn btn-primary btn-xs">编辑</button>
    <button class="btn btn-danger btn-xs">删除</button>
    </a>
    </td>
    </tr>
    <tr>
    <th scope="row">2</th>
    <td>Jacob</td>
    <td>Thornton</td>
    <td>@fat</td>
    <td>
    <a href="">
    <button class="btn btn-primary btn-xs">编辑</button>
    <button class="btn btn-danger btn-xs">删除</button>
    </a>
    </td>
    </tr>
    <tr>
    <th scope="row">3</th>
    <td>Larry</td>
    <td>the Bird</td>
    <td>@twitter</td>
    <td>
    <a href="">
    <button class="btn btn-primary btn-xs">编辑</button>
    <button class="btn btn-danger btn-xs">删除</button>
    </a>
    </td>
    </tr>
    </tbody>
    </table>
    </div>

    </div>
    <div class="text-center">
    <ul class="pagination">
    <li class="disabled"><a href="#" aria-label="Previous"><span aria-hidden="true">«</span></a>
    </li>
    <li class="active"><a href="#">1 <span class="sr-only">(current)</span></a></li>
    <li><a href="#">2</a></li>
    <li><a href="#">3</a></li>
    <li><a href="#" aria-label="Next"><span aria-hidden="true">»</span></a></li>
    </ul>
    </div>
    </div>
    </body>
    </html>
    1
    2
    3
    4
    5
    6
    7
    8
    body {
    margin: 0;
    /*background: linear-gradient(#b4d5b4, #d2c1c1);*/
    }

    .navbar {
    border-radius: 0;
    }

8.图标

图标库:

  1. Bootstrap自带的图标库(图标较少)
  2. Font Awesome(图标较多)

引入方式

1
2
3
4
5
外链式
<link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css">
<link rel="stylesheet" href="https://cdn.staticfile.org/font-awesome/4.7.0/css/font-awesome.css">
下载到本地
<link rel="stylesheet" href="/static/plugins/fontawesome-free-6.2.1-web/css/fontawesome.css">

设置样式

1
<i class="fa-solid fa-magnifying-glass" style="color:red"></i>

9.动态式响应(屏幕自适应)

1
2
head标签中设置
<meta name="viewport" content="width=device-width, initial-scale=1.0">

5.JavaScript

==for循环格式和c语言一致,object HTMLTableCellElement为DOM对象==

简介:

  • JavaScript是一门编程语言,浏览器是该语言的解释器。
  • DOM和BOM
    1. 相当于编程语言内置的模块。
    2. 例如:python中的re、random、time、json模块等。
  • Jquery
    1. 相当于编程语言的第三方模块
    2. 例如:request、OpenCV、openpyxl

意义:

让程序实现一些动态效果

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.head {
width: 200px;
border: 1px solid rebeccapurple;
}

.head .title {
background: linear-gradient(rosybrown, lightblue);
padding: 20px 10px;
}
</style>
</head>
<body>
<div class="head">
<div class="title" onclick="myFunc()">退出</div>
<div class="content">123</div>
<script type="text/javascript">
function myFunc() {
alert("是否退出?")//警告弹窗
confirm("是否退出?")
}
</script>
</div>
</body>
</html>

1.代码位置

放在head标签里或</body>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script type="text/javascript">
function myFunc() {
alert("是否退出?")
}
</script>
</head>
<body>
<script type="text/javascript">
function myFunc() {
confirm("是否退出?")
}
</script>
</body>
</html>

2.存在形式

1.内嵌式

放在html里

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script type="text/javascript">
function myFunc() {
alert("是否退出?")
}
</script>

</head>
<body>
<script type="text/javascript">
function myFunc() {
confirm("是否退出?")
}
</script>
</body>
</html>

2.外联式

html里引用,Js文件独立放置

1
2
3
4
5
6
7
8
9
10
11
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="/static/js/adminsystem.js"></script>
</head>
<body>
<script src="/static/js/adminsystem.js"></script>
</body>
</html>

3.注释

1.html

1
<!--注释内容-->

2.css

1
/*注释内容*/

3.js

1
2
//单行注释
/*注释内容*/多行注释

4.变量

1
2
3
4
5
6
7
8
9
10
11
12
13
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>变量</title>
</head>
<body>
<script type="text/javascript">
var name = "Alleyf";
console.log(name);
</script>
</body>
</html>

5.字符串类型

1.定义

1
2
3
//声明
var name = "Alleyf";
var name = String("Alleyf");

2.常见功能

1
2
3
4
5
var name = "alleyf";
var v1 = name.length;//取长度
var v2 = name[0];//索引(与name.charAt(0)等价)
var v3 = name.trim();//去除字符创空白并返回
var v4 = name.substring(0,2);//取子串相当于切片(前取后不取)

案例:跑马灯

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>变量</title>
<style>
.head {
width: 250px;
margin: 5px auto;
background: linear-gradient(rebeccapurple, blanchedalmond);
text-align: center;
}
</style>
</head>
<body>
<div class="head">
<span id="slogin" style="text-align: center;color: red">欢迎使用拂安医学文献管理系统</span>
</div>
<script type="text/javascript">
function show() {
var tag = document.getElementById("slogin");
var dataString = tag.innerText;
console.log(dataString);
// 动态显示-》循环拿文本中第一个字符放在字符串的最后面
var firstChar = dataString[0];
var otherString = dataString.substring(1, dataString.length);
var newText = otherString + firstChar;
// 在html标签中更新内容
tag.innerText = newText;
}

// 定时每秒执行一次该函数
setInterval(show, 1000)
</script>
</body>
</html>

6.数组

1
2
3
//定义
var v1 = [11,22,33,44];
var v2 = Array([11,22,33,44,55]);
1
2
3
4
5
6
7
8
9
10
11
//操作
var v1 = [11,22,33,44];
v1[1]
v1[0] = "Alleyf";
v1.push("chuiyugin");//尾部追加[11,22,33,44,"chuiyugin"]
v1.unshift("联通");//前部追加["联通",11,22,33,44]
v1.splice(索引,0,元素);
v1.splice(1,0,"中国"); //索引插入[11,"中国",22,33,44]
v1.pop() //尾部删除
v1.shift() //头部删除
v1.splice(2,1)//索引为2的元素删除[11,22,44]
1
2
3
4
5
6
7
8
9
10
var v1 = [11,22,33,44];
//循环遍历数组元素
for(var idx in v1){
data=v1[idx];//获取到的是数组的索引
console.log(data);//循环输出v1数组中的元素
}
for(var i; i<v1.length;i++)
{
data=v1[i];
}

js也可以使用breakcontinue控制循环,用法和c语言一样。

案例:动态数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<ul id="city">
<!-- <li>北京</li>-->
</ul>
<script type="text/javascript">
// 发送网络请求
var cities = ["北京", "上海", "深圳", "武汉"]
for (var cityid in cities) {
var citytext = cities[cityid];
// 创建li标签
var tag = document.createElement("li");
tag.innerText = citytext;
// 添加到id=city标签里-DOM
var city = document.getElementById("city");
city.appendChild(tag);
}
</script>
</body>
</html>

7.对象(字典)

1
2
3
4
5
6
7
8
9
info = {
"name":"Alleyf"
"age":18
}
//键可以不加双引号->实际上加不加键都是字符串类型
info = {
name:"Alleyf"
age:18
}
1
2
3
4
5
6
7
8
9
//操作
//获取对象成员
info.age
info.name="chuiyugin"

info["age"]
info["name"]="chuiyugin"
//删除
delete info["age"]
1
2
3
4
5
6
7
8
9
//循环
info = {
name:"Alleyf"
age:18
}
for(var key in info)
{
console.log(info[key]); //获取到的是对象(字典)的键(key)
}

案例:动态表格

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<table border="1">
<thead>
<tr>
<th>ID</th>
<th>姓名</th>
<th>年龄</th>
<th>年级</th>
</tr>
</thead>
<tbody id="body">

</tbody>
</table>
<script type="text/javascript">
var info = {
id: 1,
name: "Alleyf",
age: 18,
grade: 3

}
var bodytr = document.createElement("tr");
for (var key in info) {
var bodytd = document.createElement("td");
// bodytd.innerText = info[key];
bodytd.innerText = info[key];
console.log(info.key, bodytd);
bodytr.appendChild(bodytd);
}
var by = document.getElementById("body");
by.appendChild(bodytr);
</script>
</body>
</html>

8.条件语句

1
2
3
4
5
if(条件) {

}else {

}
1
2
3
4
5
6
7
8
if() {

}else if() {

}else if() {

}else {
}

9.函数

1
2
3
4
function () {
...
}
func()//执行函数

6.DOM

DOM,就是一个模块,模块可以对html页面中的标签进行操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//根据ID获取标签
var tag = document.getElementById("id");

//获取标签中的文本
tag.innerText;

//修改标签中的文本
tag.innerText = "text";

//创建标签<div>哈哈哈</div>
var tag = document.createElement("div");

//标签写内容
tag.innerText = "哈哈哈"

//给标签添加子标签
tag.appendChild(childtag);

1.事件绑定

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<input type="button" value="添加" onclick="add()">//单击响应
<input type="button" value="添加" onclick="add()">//双击响应
<ol id="info" class="fa-list-ol">

</ol>
<script type="text/javascript">
function add(data) {
var newtag = document.createElement("li")
newtag.innerText = data;
var tag = document.getElementById("info");
tag.appendChild(newtag);
}
</script>
</body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<input type="text" placeholder="请输入内容" id="txtusr" class="input-group">
<input type="button" value="添加" onclick="add()" class="input-group">
<ul id="info" class="fa-list-ol">

</ul>
<script type="text/javascript">
function add() {
// 获取用户输入的标签
var txttag = document.getElementById("txtusr");
// 获取用户输入的值
var txt = txttag.value;
// 判断用户输入是否存在
if (txt) {
// 清空用户输入
txttag.value = null;
// 新建标签
var newtag = document.createElement("li")
// 修改标签内容
newtag.innerText = txt;
var tag = document.getElementById("info");
// 添加子标签到父标签
tag.appendChild(newtag);
} else {
alert("输入不能为空")

}
}
</script>
</body>
</html>

注意:DOM中还有很多操作。

DOM可以实现很多功能,但是比较繁琐。

页面上的效果:jQuery来实现/vue.js/react.js 。

复习

1.编码

-ASCII编码,256种对应关系

-gb2312,gbk,中文和亚洲的一些国家【中文是两个字节】

-unicode,ucs2、ucs4,包括现在发现的所有文明

-utf-8编码,压缩的unicode编码【中文是3个字节】

python默认解释器编码: utf-8

2.字符串格式化

1
2
3
4
5
v1 = "我是{},今年{}".format("牛牛"23)
v2 = "我是%s,今年%d岁" %("牛牛"18)
name = "牛牛"
age = 18
v3 = f"我是{name},今年{age}岁"

3.数据类型

常见数据类型:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
int/bool/str/list/tuple/list/dict/set/float/None
转化为boolFalse:空、None0
可变和不可变划分,可变的有:listsetdict
可哈希和不可哈希,不可哈希的有:listsetdict
字典的键/集合的元素,必须是可哈希的类型(listsetdict不能做字典的建和集合元素)

主要数据类型:
str
独有功能:split、upper、lower、startswith、strip、join
注意:原str本身不变,是生成新的字符串。
公共功能:len、索引、切片、for循环、判断是否包含
list
独有功能:append、insert、remove、pop···
公共功能:len、索引、切片、for循环、判断是否包含
注意:list可变,功能很多都是对原数据操作
dict
独有功能:get/keys/items/values
公共功能:len、索引for循环、、判断是否包含(判断键效率很高)

4.运算符

1
2
3
4
5
6
基本运算符:加减乘除···
特殊逻辑运算:
1>2 and 3>10
v1 = 99 and 88 #88
v2 = [] or 10 #10
v3 = '联通' or [] #'联通'

5.推导式(简化生成数据)

1
2
3
4
5
6
data = []
for i in range(10):
data.append(i)

data = [i for in range(10)]
data = [i for in range(10) if i<5] #[0,1,2,3,4]

6.函数编程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
函数的基础知识:
定义
参数,概念:位置参数、关键字参数、参数默认值、动态参数*args,**kwargs
返回值
函数中一旦遇到return就立即返回,后续代码不再执行。
函数没有返回值默认返回None
函数的进阶:
python中是以函数为作用域
全局变量和局部变量,规范:全局变量(大写)、局部变量(小写)
在局部变量中的可以使用global关键词,global的作用?引用全局的那个变量(不是在局部创建)。

内置函数(python内部提供的函数):
bin/hex/odc/max/min/divmod/sorted(按照unicode码表排序)/open(文件操作)

文件操作:
基本操作:打开、操作、关闭,为了防止忘记关闭文件,可以怎么做?with
打开文件时有莫事:
r/rb,读 【文件或者目录或者文件夹不存在,报错】
w/wb,写(清空)【文件不存在,自动新建】
a/ab,追加 【文件不存在,自动新建】
注意:os.makedirs/os.path.exists,是否存在、不存在新建目录。

7.模块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
模块的分类:
自定义模块:
os.path,导入模块时python内部都会去那个目录找
自己写py文件时,不要与python内置模块同名。
import/from xx import xx
内置模块:time/datetime/json/re/random/os···
第三方模块:requests/openpyx1/python-docx/flask/bs4

查看当前目录下所有的文件:os.listdir(获取当前目录的文件一级目录)/os.walk(获取当前目录下所有的目录),os.path.splitext():分离文件名与扩展名
关于时间模块:时间戳、datetime格式、字符串,三种时间格式可以相互转化。
关于JSON模块:
JSON本质是字符串,有一些自己格式的要求,例如:无元组、无单引号。
json.dumps(功能是将字典类型转换为json格式的字符串类型)序列化时,只能序列化Python常用数据类型。
关于re正则模块:
正则:\d \w
贪婪匹配(默认)和非贪婪匹配,不贪婪则设置个数后面加?
re.search/re.match/re.findall

第三方模块:
安装方式:pip管理工具、源码、wheel包
image-20221206000610118

8.面向对象

1
2
目标:不是为了用面向对象编程(推荐使用函数编程,面向对象要看得懂)。
面向对象三大特性:封装、继承、多态。

9.前端开发

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
前端知识点三部分:
HTML,标签具有模式特点。
CSS,修改标签的特点。
JavaScript,动态。

HTML标签
div/span/a/img/input/form/table/ul/ol```
块级和行内标签,例如:div span 默认谁是块级标签?div
注意:css样式,发现行内标签设置高度、宽度、内边距、外边距都是无效。
form表单+input/select/textarea 数据框
action:提交地址
method:提交方式
form标签中有一个submit
内部标签都需要设置name属性

CSS样式
布局样式:div+float(脱离文档流,clear:both;clearfix)
高度和宽度
边距
内边距
外边距
字体、大小、颜色、粗细
边框
背景颜色(linear-grident可设置渐变色)
hover,鼠标放上去就会触发的CSS样式

7.JQuery

jquery是一个javascript第三方模块(第三方库)。

  • 基于Jquery,自己开发一个功能。
  • 现成的工具依赖JQuery,例如:BootStrap动态效果。

1.快速上手

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1 id="txt">中国联通</h1>

<script src="/static/plugins/jquery-3.6.1.min.js"></script>
<script type="text/javascript">
// 找到标签
let txt = $("#txt")
txt.text("中国移动")
</script>
</body>
</html>

2.寻找标签(直接寻找)

  1. ID

    1
    <h1 id="txt">中国联通</h1>
    1
    $("#txt")
  2. 样式(类)选择器

    1
    <h1 class="c1">中国联通</h1>
    1
    $(".c1")
  3. 标签选择器

    1
    <h1>中国联通</h1>
    1
    $("h1")
  4. 层级选择器

    1
    2
    3
    4
    5
    <div class="c1">
    <span class="c2">
    <a href="#"></a>
    </span>
    </div>
    1
    $(".c1.c2 a")
  5. 多选择器

    1
    2
    3
    4
    5
    6
    7
    8
    <div class="c1">
    <span class="c2"></span>
    <a href="#"></a>
    </div>
    <ul id="u1">
    <li></li>
    </ul>
    <p class="p1"></p>
    1
    $(".c1,#u1,p")
  6. 属性选择器

    1
    2
    <input type="text" name="n1">
    <input type="text" name="n2">
    1
    $("input[name='n1']")

3.间接寻找

  • 找到上一个兄弟

    1
    2
    3
    4
    5
    6
    <div>
    <div>北京</div>
    <div id="c1">上海</div>
    <div>广州</div>
    <div>深圳</div>
    </div>
    1
    2
    3
    4
    5
    $("#c1").prev()	//上一个
    $("#c1")
    $("#c1").next() //下一个
    $("#c1").next().next() //下下一个
    $("#c1").siblings() //所有同级标签(兄弟)
  • 找父子

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <div>
    <div>
    <div id="c1">上海</div>
    </div>
    </div>

    <div id="c2">
    <div>老大</div>
    <div class="d2">老二</div>
    </div>
    1
    2
    3
    4
    5
    6
    $("#c1").parent()	//父亲
    $("#c1").parent().parent() //祖父
    $("#c2").children() //所有孩子
    $("#c2").children(".d2") //所有的孩子中寻找class=d2的孩子
    $("#c2").find(".d2") //去寻找class=d2的所有子孙
    $("#c2").find("div") //去寻找div标签的所有子孙

案例:菜单的切换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.menu {
width: 200px;
height: 800px;
border: 1px solid red;
}

.menu .header {
cursor: pointer;
padding: 10px 5px;
border-bottom: 1px dotted #ddd;
background: linear-gradient(gold, lightblue);
}

.item a {
display: block;
text-decoration: none;
padding: 5px 5px;
border-bottom: 1px dotted #ddd;
}

.hide {
display: none;
}
</style>
</head>
<body>
<div class="menu">
<div class="item">
<div class="header" onclick="clickme(this)">北京</div>
<div class="content hide">
<a href="">海淀区</a>
<a href="">朝阳区</a>
<a href="">大兴区</a>
<a href="">昌平区</a>
</div>
<div class="header" onclick="clickme(this)">上海</div>
<div class="content hide">
<a href="">宝山区</a>
<a href="">普陀区</a>
<a href="">浦东新区</a>
<a href="">青浦区</a>
</div>
</div>
</div>
<script src="/static/plugins/jquery-3.6.1.min.js"></script>
<script>
//方法一
// let i = 0;
// function clickme(self) {
// if (i++ % 2 === 0) {
// $(self).next().removeClass("hide");
// } else {
// $(self).next().addClass("hide");
// }
// }
//方法二
function clickme(self) {
var hasHide = $(self).next().hasClass("hide")
if (hasHide) {
$(self).next().removeClass("hide");
} else {
$(self).next().addClass("hide");
}
}
</script>
</body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
//只展示单个菜单
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.menu {
width: 200px;
height: 800px;
border: 1px solid red;
}

.menu .header {
cursor: pointer;
padding: 10px 5px;
border-bottom: 1px dotted #ddd;
background: linear-gradient(#a7e3c9, lightblue);
}

.item a {
display: block;
text-decoration: none;
padding: 5px 5px;
border-bottom: 1px dotted #ddd;
}

.hide {
display: none;
}
</style>
</head>
<body>
<div class="menu">
<div class="item">
<div class="header" onclick="clickme(this)">北京</div>
<div class="content hide">
<a href="">海淀区</a>
<a href="">朝阳区</a>
<a href="">大兴区</a>
<a href="">昌平区</a>
</div>
</div>
<div class=item>
<div class="header" onclick="clickme(this)">上海</div>
<div class="content hide">
<a href="">宝山区</a>
<a href="">普陀区</a>
<a href="">浦东新区</a>
<a href="">青浦区</a>
</div>
</div>
<div class="item">
<div class="header" onclick="clickme(this)">武汉</div>
<div class="content hide">
<a href="">洪山区</a>
<a href="">江汉区</a>
<a href="">武昌区</a>
<a href="">青山区</a>
</div>
</div>

</div>
<script src="/static/plugins/jquery-3.6.1.min.js"></script>
<script>
function clickme(self) {
var hasHide = $(self).next().hasClass("hide")
if (hasHide) {
// 展示自己
$(self).next().removeClass("hide");
// 隐藏别人
$(self).parent().siblings().find(".content").addClass("hide")
} else {
$(self).next().addClass("hide");
}
}
</script>
</body>
</html>

4.操作样式

  • addClass

  • removeClass

  • hasClass

5.值的操作

1
<div id="c1">内容</div>
1
2
$("#c1").text() //获取内容
$("#c1").text("测试") //设置内容
1
<input type="text" id="c2">
1
2
$("c2").val()   //获取用户输入值
$("c2").val("txt") //设置用户输入值

案例:输入内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<input type="text" id="txtUser" placeholder="用户名">
<input type="text" id="txtEmail" placeholder="邮箱">
<input type="button" value="提交" onclick="getinfo()">
<ul id="view">

</ul>


<script src="/static/plugins/jquery-3.6.1.min.js"></script>
<script>
function getinfo() {
let username = $("#txtUser").val(); //设置用户输入值
let email = $("#txtEmail").val();
const datastr = username + '-' + email;
let lusr = $("<li>").text(datastr);
$("#view").append(lusr);

}
</script>
</body>
</html>

6.事件

绑定事件直接用$("")获取到标签直接定义事件即可

1
2
3
4
$(".item").children().click(function () {
$(this).text("hello python")
$(this).remove()
})

案例:设置内容和删除

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.item a {
display: block;
text-decoration: none;
}
</style>
</head>
<body>
<div class="item">
<p href="">1</p>
<p href="">2</p>
<p href="">3</p>
</div>


<script src="/static/plugins/jquery-3.6.1.min.js"></script>
<script>
let a = $(".item").children()
$(a).click(function () {
$(this).text("hello python")
$(this).remove()
})
</script>
</body>
</html>

当页面框架加载完成之后执行代码(封装在$function之内):

1
2
3
4
5
6
7
<script>
$(function () {
$(".item").children().click(function () {
$(this).text("hello python");
})
})
</script>

案例:表格操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<table border="1">
<thead>
<tr>
<th>ID</th>
<th>姓名</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>Alleyf</td>
<td>
<input type="button" value="删除" class="delete">
</td>
</tr>
<tr>
<td>1</td>
<td>Alleyf</td>
<td>
<input type="button" value="删除" class="delete">
</td>
</tr>
<tr>
<td>1</td>
<td>Alleyf</td>
<td>
<input type="button" value="删除" class="delete">
</td>
</tr>
</tbody>
</table>
<script src="/static/plugins/jquery-3.6.1.min.js"></script>
<script>
$(function () {
// 找到所有class为delete的标签
$(".delete").click(function () {
// 删除当前行
$(this).parent().parent().remove();
})
})
</script>
</body>
</html>

8.前端整合

  • HTML
  • CSS
  • JavaScript、jQuery
  • Bootstrap(动态效果依赖jQuery)

案例:添加数据页面

人员信息录入功能,需要提供用户信息:

用户名、年龄、薪资、部门、入职时间(*)

时间的选择:不能输入;选择:(插件)datetimepicker

  • 下载插件
  • 应用插件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="">
<link rel="stylesheet" href="/static/plugins/bootstrap-datetimepicker-master/css/bootstrap-datetimepicker.css">
<link rel="stylesheet" href="/static/plugins/bootstrap-3.4.1/css/bootstrap.css">
<link rel="stylesheet" href="/static/plugins/fontawesome-free-6.2.1-web/css/fontawesome.css">
</head>
<body>
<div class="container" style="margin-top: 20px">
<form class="form-horizontal">
<div class="row clearfix">
<div class="col-sm-6">
<div class="form-group">
<label for="inputEmail3" class="col-sm-2 control-label">姓名</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="inputEmail3" placeholder="姓名">
</div>
</div>
</div>
<div class="col-sm-6">
<div class="form-group">
<label for="inputPassword3" class="col-sm-2 control-label">年龄</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="inputPassword3" placeholder="年龄">
</div>
</div>
</div>
</div>
<div class="row clearfix">
<div class="col-sm-6">
<div class="form-group">
<label for="inputsalary" class="col-sm-2 control-label">薪资</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="inputsalary" placeholder="薪资">
</div>
</div>
</div>
<div class="col-sm-6">
<div class="form-group">
<label for="inputbranch" class="col-sm-2 control-label">部门</label>
<div class="col-sm-10">
<select class="form-control" name="brabch" id="inputbranch">
<option value="">IT部门</option>
<option value="">销售部门</option>
<option value="">人事资源管理部门</option>
<option value="">售后部门</option>
<option value="">运营部门</option>
</select>
</div>
</div>
</div>
</div>
<div class="row clearfix">
<div class="col-sm-6">
<div class="form-group">
<label for="dt" class="col-sm-2 control-label">入职日期</label>
<div class="col-sm-10">
<input type="text" id="dt" class="form-control" placeholder="入职日期">
</div>
</div>
</div>
<div class="col-sm-6">
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label>
<input type="checkbox"> 一切信息属实
</label>
</div>
</div>
</div>
</div>
</div>
<div class="row clearfix">
<div class="col-sm-6">
<div class="form-group ">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-primary">提交</button>
</div>
</div>
</div>
</div>

</form>
</div>

<script src="https://kit.fontawesome.com/2503dce09a.js" crossorigin="anonymous"></script>
<script src="/static/js/jquery-3.6.1.min.js"></script>
<script src="/static/plugins/bootstrap-3.4.1/js/bootstrap.js"></script>
<script src="/static/plugins/bootstrap-datetimepicker-master/js/bootstrap-datetimepicker.js"></script>
<script src="/static/plugins/bootstrap-datetimepicker-master/js/locales/bootstrap-datetimepicker.zh-CN.js"></script>
<script>
$(function () {
$('#dt').datetimepicker({
fomat: 'yyyy-mm-dd',
startDate: '0',
language: 'zh-CN',
autoclose: true
});
})
</script>
</body>
</html>

9.MySQL

重装

CentOS 是一种非常流行的 Linux 发行版,它具有强大的性能和稳定性,被广泛应用于各种互联网服务。其中,MySQL 是一种常用的关系型数据库管理系统,用于存储和管理各种类型的数。但是在使用 CentOS 系统的过程中,有时候需要重装 MySQL,本文将介绍如何在 CentOS 系统中进行 MySQL 的重装。

步骤如下:

  1. 卸载已安装的MySQL
1
2
sudo systemctl stop mysqld
sudo yum remove mysql mysql-server mysql-libs
  1. 清除遗留文件
1
2
sudo rm -rf /var/lib/mysql
sudo rm -rf /etc/my.cnf
  1. 下载并安装新版 MySQL
1
2
3
sudo wget -i -c http://dev.mysql.com/get/mysql57-community-release-el7-10.noarch.rpm
sudo rpm -ivh mysql57-community-release-el7-10.noarch.rpm
sudo yum install mysql-server
  1. 启动 MySQL 服务
1
2
sudo systemctl start mysqld
sudo systemctl enable mysqld
  1. 初始化 MySQL
1
sudo mysql_secure_installation

以上就是在CentOS系统中重装MySQL的步骤,需要注意的是,重装MySQL会清除所有数据,因此在操作之前需要备份好数据。如果不是必须要重装MySQL的情况下,建议先尝试修复已有的MySQL。

1.种类

MySQL、Oracle、SQLServer、DB2、Access···

2.基本操作

2.1查看已有数据库(文件夹)

1
show databases;

2.2退出

1
exit;

2.3设置数据库密码

关闭MYSQL服务

1
set password = password('123456');

3.数据类型

类型 用途
tinyint 短整形(),相当于java的short,有符号(默认),取值范围:-128~127;无符号(用关键词unsigned指定),取值范围:0~255
int 整形,相当于java的int
bigint 长整形,相当于java的long
float 单精度浮点型
double 双精度浮点型
decimal 准确的小数值,eg:wage decimal(m,n) –总共m位数(负号不算),其中小数点后有n位,mmax=65,nmax=30.
datatime 日期类型,YYYY-MM-DD HH:MM:SS(2022-12-09 21:03:00),dt转为字符串类型显示(dt.strftime(“%Y-%m-%d %H:%M:%S”))
data 日期类型(无时分秒)YYYY-MM-DD
timestamp 日期类型(可存储时间戳)
char 定长字符,固定字符长度,最大255个字符,速度快,常存储:手机号,邮箱,加密后的密码等
varchar 不定长字符,有多少存多少,最大65535个字节,节省空间
text 大文字,用于存储很长的字符内容,可存储65535个字符,例如:文章,新闻等。
mediumtext 中等文本,最多存储16777215(2^24^-1)个字符
longtext 长文本,最多存储4294967295(4GB)(2^32^-1)个字符
blob 字节数据类型,存储图片、音频等文件

4.MYSQL指令

4.1数据库管理

  • 查看当前已有数据库

    1
    show databases;
  • 创建数据库

    1
    2
    create database 数据库名;
    create database 数据库名 DEFAULT CHARSET utf8 COLLATE utf8_general_ci;
  • 删除数据库

    1
    drop database 数据库名;
  • 进入数据库

    1
    use 数据库名;
  • 查看当前数据库下的所有数据表

    1
    show tables;

4.2数据表管理

  • 创建表

    1
    2
    3
    4
    5
    6
    create table 表名(
    字段名 类型,
    字段名 类型,
    ···
    字段名 类型
    )default charset=utf8;
    1
    2
    3
    4
    5
    6
    7
    create table 表名(
    字段名 类型 not null auto_increment primary key, --主键(不允许为空,不允许重复)自增特性
    字段名 类型 not null--不允许为空
    字段名 类型 default 1--插入数据时,默认值为1
    ···
    字段名 类型 null --允许为空(默认)
    )default charset=utf8;

    ==主键一般用于表示当前行的编号==(类似于身份证)。

​ 示例

1
2
3
4
5
create table medocsys(
id int not null auto_increment primary key,
name varchar(20) not null,
pwd varchar(15) not null
) default charset=utf8;
  • 查看创建的表信息

    1
    desc 表名
  • 插入数据

    1
    2
    3
    4
    单条插入
    insert into 表名(字段名1,字段名2,···,字段名) values(数据1,数据2,···,数据);
    批量插入
    insert into 表名(字段名1,字段名2,···,字段名) values(数据1,数据2,···,数据),(数据1,数据2,···,数据),···(数据1,数据2,···,数据);

4.5数据行操作

1.新增数据
1
2
3
4
单条插入
insert into 表名(字段名1,字段名2,···,字段名) values(数据1,数据2,···,数据);
批量插入
insert into 表名(字段名1,字段名2,···,字段名) values(数据1,数据2,···,数据),(数据1,数据2,···,数据),···(数据1,数据2,···,数据);
2.删除数据
1
2
delete from 表名;--删除所有数据
delete from 表名 where 条件;--删除满足条件的数据

delete from tb1 where id>=10 or name=”alleyf”;

3.修改数据
1
2
3
4
update 表名 set 字段名=值;
update 表名 set 字段名1=值,字段名2=值;
update 表名 set 字段名=where 条件;
eg:update medocsys set name="alley", pwd=pwd+"10";
4.查询数据
1
2
3
4
5
6
查询表所有数据
select * from 表名;
查询对应字段的数据
select 字段名1,字段名2 from 表名;
条件查询数据
select * from 表名 where id > 3

小结

一般开发:

  • 创建数据库
  • 创建数据表

==提前用工具创建好==

  • 增删改查表的数据

==用程序实现==

==mysql命令可以先用占位符%s填充,在execute中添加列表来代替占位符==

1
cursor.execute("select * from user where id > %s", [2,])

在进行增删改的时候需要执行commit,不然数据库没有数据

1
2
cursor.execute("```")
cnet.commit()

在进行查询的时候不需要执行commit,但是要执行fetchall/fetchone获取到返回的数据

1
2
3
4
5
cursor.execute(sql)
# 获取返回的所有数据(包含字典成员的列表)
return cursor.fetchall()
# 获取返回的第一条数据
# return cursor.fetchone()
案例:用户管理
  • 表结构创建

    1
    2
    3
    4
    5
    6
    7
    create table user(
    id int not null auto_increment primary key,
    name varchar(20) not null,
    pwd char(12) not null,
    phonenumber char(11) not null,
    email char(20) not null
    ) default charset=utf8;
  • python操作数据库

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    import pymysql


    # 连接数据库
    def cnetsql(host, port, user, passwd, db, charset="utf8"):
    tempcnet = pymysql.connect(host=host, port=port, user=user, passwd=passwd, charset=charset, db=db)
    tempcursor = tempcnet.cursor(cursor=pymysql.cursors.DictCursor)
    return tempcnet, tempcursor


    cnet, cursor = cnetsql(host="127.0.0.1", port=3306, user="root", passwd="123456", db="medocsys")


    # ID重新排序
    def idsort():
    delid = "ALTER TABLE user DROP id"
    addid = "ALTER TABLE user ADD id int NOT NULL FIRST"
    setprimary = "ALTER TABLE user MODIFY COLUMN id int NOT NULL AUTO_INCREMENT,ADD PRIMARY KEY(id)"
    sqls = [delid, addid, setprimary]
    # sqls = [addid, setprimary]
    for sql in sqls:
    cursor.execute(sql)
    cnet.commit()


    # 增加数据
    def insert(tablename, fieldnames, fieldvalues):
    basestr1 = "insert into "
    basestr2 = "values"
    basestr3 = "("
    basestr4 = ")"
    basestr5 = " "
    # 字段名列表转字符串
    length = len(fieldnames)
    fieldnames = ','.join(fieldnames)
    # # 字段值列表转字符串
    # fieldvalues = ','.join(fieldvalues)
    if not (tablename or fieldnames or fieldvalues):
    print("添加失败")
    closesql()
    return False
    else:
    fieldvaluesls = []
    fieldvaluessign = None
    print(length)
    for i in range(length):
    fieldvaluesls.append('%s')
    fieldvaluessign = ','.join(fieldvaluesls)
    print(fieldvaluessign)
    # sql = basestr1 + tablename + basestr3 + fieldnames + basestr4 + basestr5 + basestr2 + basestr3 + fieldvalues + basestr4
    sql = basestr1 + tablename + basestr3 + fieldnames + basestr4 + basestr5 + basestr2 + basestr3 + fieldvaluessign + basestr4
    print(sql)
    cursor.execute(sql, fieldvalues)
    cnet.commit()
    idsort()
    print("添加成功")
    return True


    # 查询数据
    def querydata(tablename, fieldnames=None, condition=''):
    if fieldnames is None:
    fieldnames = ['*']
    fieldnames = ','.join(fieldnames)
    sql = "select " + fieldnames + ' ' + "from " + tablename + ' ' + condition
    print(sql)
    cursor.execute(sql)
    # 获取返回的所有数据(包含字典成员的列表)
    return cursor.fetchall()
    # 获取返回的第一条数据
    # return cursor.fetchone()


    # 更新数据


    # 删除数据
    def delalldata(tablename, condition=None):
    if condition is None:
    condition = ''
    sql = "delete from " + tablename + ' ' + condition
    cursor.execute(sql)
    cnet.commit()
    idsort()


    # 关闭连接
    def closesql():
    cursor.close()
    cnet.close()


    def main():
    # idsort()
    delalldata(tablename='user')
    insert(tablename='user', fieldnames=['name', 'pwd', 'phonenumber', 'email'],
    fieldvalues=['alleyf', '123456', '13669156253', 'alleyf@qq.com'])
    info = querydata(tablename='user')
    for user in info:
    print(user)
    # delalldata(tablename='user', condition='where id = 1')


    main()

综合案例:用户注册

  • ==前端页面==
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>用户注册</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="/static/plugins/bootstrap-3.4.1/css/bootstrap.css">
<link rel="stylesheet" href="/static/plugins/fontawesome-free-6.2.1-web/css/fontawesome.css">
<link rel="stylesheet" href="/static/css/register.css">
<style>
body {
margin: 0;
padding: 0;
}

html, body {
width: 100%;
height: 100%;
}

.size {
width: 100%;
height: 100%;
}

#vcode {
height: 35px;
width: 50%;
display: inline-block;
/*padding-left: 8px;*/
}

#code {
color: #ffffff;
/*字体颜色白色*/
background: linear-gradient(plum, powderblue);
height: 35px;
width: 150px;
float: right;
text-align: center;
font-size: 18pt;
/*margin: 5px auto;*/
/*font-family: "华康娃娃体W5";*/
padding: 5px 35px 10px 35px;
margin-left: 5%;
cursor: pointer;
}
</style>
</head>
<body>

<div class="container size">
<div class="login-wrapper">
<form action="/register" method="post" onsubmit="return check()">
<div class="header">Register</div>
<div class="form-wrapper clearfix">
<input type="text" id="name" name="name" placeholder="username" class="input-item">
<input type="password" id="pwd" name="pwd" placeholder="password" class="input-item">
<input type="text" id="number" name="phonenumber" placeholder="phonenumber" class="input-item">
<input type="email" id="email" name="email" placeholder="email" class="input-item">
<input type="text" id="vcode" placeholder="verification code" class="input-item"
/><span id="code"></span>
<input class="sub" type="submit" value="Login"></input>
</div>
<div class="msg">
Do have account? <a href="#">Login in</a>
</div>
</form>
</div>
</div>

<script type="text/javascript">

var code; //声明一个变量用于存储生成的验证码
changeImg();
document.getElementById("code").onclick = changeImg;


function changeImg() {
var arrays = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
'u', 'v', 'w', 'x', 'y', 'z',
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
'U', 'V', 'W', 'X', 'Y', 'Z'];
code = ''; //重新初始化验证码
//alert(arrays.length);
//随机从数组中获取四个元素组成验证码
for (var i = 0; i < 4; i++) {
//随机获取一个数组的下标
var r = parseInt(Math.random() * arrays.length);
code += arrays[r];
}
document.getElementById('code').innerHTML = code; //将验证码写入指定区域
}

//效验验证码(表单被提交时触发)
function check() {

//获取用户输入的验证码
var input_code = document.getElementById('vcode').value;
let username = $("#name").val();
let pwd = $("#pwd").val();
let number = $("#number").val();
let email = $("#email").val();
console.log(username, pwd, number, email);
if (!(username && pwd && number && email)) {
alert("输入信息不完整,请继续输入");
return false;
}
if (input_code.toLowerCase() === code.toLowerCase()) {
//验证码正确(表单提交)
return true;
} else {
alert("请输入正确的验证码!");
//验证码不正确,表单不允许提交
return false;
}
}

</script>
<script src="https://kit.fontawesome.com/2503dce09a.js" crossorigin="anonymous"></script>
<script src="/static/js/jquery-3.6.1.min.js"></script>
<script src="/static/plugins/bootstrap-3.4.1/js/bootstrap.js"></script>
</body>
</html>

==Flask后端==

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
from flask import Flask, render_template, request
from model.cnetmysql import delalldata
from model.cnetmysql import insert
from model.cnetmysql import querydata

app = Flask(__name__)


@app.route("/register", methods=["GET", "POST"])
def register():
if request.method == "GET":
return render_template("register.html")
elif request.method == "POST":
name = request.form.get('name')
pwd = request.form.get('pwd')
phonenumber = request.form.get('phonenumber')
email = request.form.get('email')
print(request.form)
# delalldata(tablename='user', condition='where id>1')
# 添加用户
insert(tablename='user', fieldnames=['name', 'pwd', 'phonenumber', 'email'],
fieldvalues=[name, pwd, phonenumber, email])
# 查询用户
userls = querydata(tablename='user', condition='where id = 1')
adminer = userls[0]
# print(adminer)
return render_template("demo.html", adminer=adminer)


@app.route("/demo", methods=["GET", "POST"])
def demo():
if request.method == 'GET':
userls = querydata(tablename='user', condition='where id = 1')
adminer = userls[0]
return render_template('demo.html', adminer=adminer)


if __name__ == '__main__':
app.run()

10.Django

0运行目录

==django项目运行的目录为工程下的根目录(manage.py或app文件夹同级目录)==

1创建项目

  1. ==基于命令行创建==
  • 打开终端

  • 进入某个目录(希望项目存放的目录)

    1
    E:\PythonProjects\Django\Django1>
  • 执行命令创建项目

    1
    django-admin startproject Django1
    image-20221210195650923
  1. ==基于Pycharm创建==
  • 在这里插入图片描述
  1. ==默认文件介绍==
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
│  manage.py	【项目的管理,启动项目,创建app,数据管理】【不能动】【常常用】

├─.idea
│ │ .gitignore
│ │ misc.xml
│ │ modules.xml
│ │ mysite.iml
│ │ workspace.xml
│ │
│ └─inspectionProfiles
│ profiles_settings.xml

├─mysite
│ │ settings.py 【项目配置文件】【常修改】
│ │ urls.py 【URL和函数的对应关系】【常修改】
│ │ asgi.py 【接收网络请求】【不能动】
│ │ wsgi.py 【接收网络请求】【不能动】
│ │ __init__.py
│ │
│ └─__pycache__
│ settings.cpython-310.pyc
│ __init__.cpython-310.pyc

└─__pycache__
manage.cpython-310.pyc

2.APP

1
2
3
4
5
6
7
-项目
-app,用户管理【表结构、函数、HTML模板、CSS等独立】
-app,订单管理【表结构、函数、HTML模板、CSS等独立】
-app,后台管理【表结构、函数、HTML模板、CSS等独立】
-app,网站管理【表结构、函数、HTML模板、CSS等独立】
-app,API 【表结构、函数、HTML模板、CSS等独立】
···
1
2
3
4
5
6
7
8
9
10
├─app1
│ │ admin.py 【固定,不用动】django默认提供了admin后台管理
│ │ apps.py 【固定,不用动】app启动类
│ │ models.py 【重要,模型层】对数据库操作
│ │ tests.py 【固定,不用动】单元测试
│ │ views.py 【重要,视图层】前后端交互处理请求返回结果的函数
│ │ __init__.py
│ │
│ └─migrations 【固定,不用动】数据库变更记录
│ __init__.py

3.快速上手

  • 确保app已注册【setting.py】

    1
    2
    3
    4
    5
    6
    7
    8
    INSTALLED_APPS = [
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.messages",
    "django.contrib.staticfiles",
    "app1.apps.App1Config" #注册app01
  • 编写URL和视图函数对应关系【urls.py】

    1
    2
    3
    4
    5
    6
    7
    8
    from django.contrib import admin
    from django.urls import path
    from app1 import views

    urlpatterns = [
    # path("admin/", admin.site.urls),
    path("index/", views.index),
    ]
  • 编写视图函数【view.py】

    1
    2
    3
    4
    5
    6
    from django.shortcuts import render, HttpResponse


    # Create your views here.
    def index(request):
    return HttpResponse("欢迎访问拂安博客")
  • 启动Django项目

    1
    2
    3
    4
    1.命令行启动
    python manage.py runserver
    2.pycharm启动
    直接点击pycharm里的启动按钮

3.1在写一个页面

1
2
3
def register(request):
# 根据app注册顺序,去每个app目录下的templates中寻找对应的html
return render(request, "register.html")

3.2templates模板

image-20221210211237018

3.3静态文件

一般开发过程中:

  • 图片
  • CSS
  • Js

都会当做静态文件处理

3.3.1static目录

在app目录下新建static文件夹

image-20221210215416849

3.3.2引用路径静态文件

4.模板语法

本质上:在html中写一些占位符,由数据对这些占位符进行替换和处理

注意:取单独值的时候用.进行索引

1
2
3
4
5
6
7
8
9
10
视图层(view.py)
def index(request):
if request.method == 'GET':
name = 'alleyf'
# 传递值需要用字典作为参数
# 字典中包含列表,通过key.index获取列表中的某个元素
dit = {'name': name}
hobby = ['java', 'python', 'C++', 'Go']
userinfo = {'name': 'alleyf', 'age': 20, 'gender': 'boy'}
return render(request, 'demo.html', dit)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
前端(template中的html文件)
-字符串键值对
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">{{ name }} <span class="caret"></span></a>
-列表键值对
<li><a href="#">{{ hobby.0 }}</a></li>
<li><a href="#">{{ hobby.1 }}</a></li>
<li><a href="#">{{ hobby.2 }}</a></li>
-字典键值对
<ol>
<li>{{ userinfo }}</li>
<li>{{ userinfo.name }}</li>
<li>{{ userinfo.age }}</li>
<li>{{ userinfo.gender }}</li>
</ol>
-列表里套字典
<li>{{ datalist.0.name }}</li>
<li>{{ datalist.0.hobby }}</li>

==循环语句==

l是列表

1
2
3
{% for item in l %}
<span>{{ item }}</span>
{% endfor %}

d是字典

1
2
3
4
5
6
7
8
9
10
11
12
-取字典中键
{% for key in userinfo.keys %}
<li>{{ key }}</li>
{% endfor %}
-取字典中键
{% for value in userinfo.values %}
<li>{{ value }}</li>
{% endfor %}
-取字典中键值对
{% for k,v in userinfo.items %}
<li>{{ k }}={{ v }}</li>
{% endfor %}

列表套字典datalist为列表,info为字典

1
2
3
{% for info in datalist %}
<li>{{ info.name }}--{{ info.hobby }}</li>
{% endfor %}

==条件语句==

1
2
3
4
5
6
7
{% if hobby.0 == 'java' %}
<h1>{{ hobby.0 }}==java</h1>
{% elif hobby.0 == 'python' %}
<h1>{{ hobby.0 }}==python</h1>
{% else %}
<h1>{{ hobby.0 }}==其他</h1>
{% endif %}

案例:热搜展示

view.py

1
2
3
4
5
6
7
8
def news(request):
url = "http://api.54dh.cn/API/search/rs/?type=weibo"
dic = {'user-agent': 'Mozilla/5.0'}
r = requests.post(url, headers=dic)
r.raise_for_status()
r.encoding = r.apparent_encoding
info = {'info': r.json()}
return render(request, "news.html", info)

news.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>每日一言</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="{% static 'plugins/bootstrap-3.4.1/css/bootstrap.css' %}">
<link rel="stylesheet" href="{% static 'plugins/fontawesome-free-6.2.1-web/css/fontawesome.css' %}">
{# <link rel="stylesheet" href="{% static 'css/register.css' %}">#}
<style>
* {
padding: 0;
margin: 0;
font-family: 微软雅黑, serif;
letter-spacing: .05em;
}
.container {
margin: 5px auto;
background-image: linear-gradient(to right, #fbc2eb, #a6c1ee);
}

</style>
</head>
<body>
<div class="container text-center">
{% for item in info.data %}
<a href="{{ item.link }}">{{ item.title }}--{{ item.heat }}</a>
<br>
{% endfor %}
</div>
<script src="https://kit.fontawesome.com/2503dce09a.js" crossorigin="anonymous"></script>
<script src="{% static 'js/jquery-3.6.1.min.js' %}"></script>
<script src="{% static 'plugins/bootstrap-3.4.1/js/bootstrap.js' %}"></script>
</body>
</html>

5.请求和响应

通过此方式可以获取到get请求中的参数和post请求中的数据

1
2
3
4
5
6
7
8
9
def something(request):
if request.method == "GET":
# 获取get请求中携带的参数
parameters = request.GET
# 获取post请求中提交的数据
data = request.POST
print(parameters)
print(data)
return HttpResponse(parameters['name'])

重定向:返回重定向的网址给浏览器,浏览器去请求该网址

1
2
3
4
5
6
def register(request):
if request.method == "GET":
# 根据app注册顺序,去每个app目录下的templates中寻找对应的html
return render(request, "register.html")
elif request.method == "POST":
return redirect(request, 'login.html')

案例:用户登录

post请求后的错误

image-20221211163414687

解决办法

在html表单(form)中加上{% csrf_token %}

image-20221211164710327

6.数据库操作

Django使用ORM框架实现对数据库的操作,安装mysqlclient第三方库辅助操作

1
pip install mysqlclient

1.ORM

ORM可以帮助我们完成两件事:

  1. 创建、修改、删除数据库中的表(不用写SQL语句)【无法创建数据库】

  2. 操作表中的数据

    1
    2
    3
    4
    insert into```
    update
    delete
    select

2.配置setting.py文件

1
2
3
4
5
6
7
8
9
10
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql', #连接MYSQL数据库
'NAME': 'medocsys', # 数据库名
'USER': 'root', # 数据库用户名
'PASSWORD': '123456', # 数据库密码
'HOST': '127.0.0.1', # 数据库主机地址
'PORT': 3306, # 数据库连接端口号
}
}

3.Django操作表

1.创建表

在models.py中创建表类

1
2
3
4
5
6
7
# Create your models here.
class Userinfo(models.Model):
name = models.CharField(max_length=32)
password = models.CharField(max_length=64)
mobile = models.CharField(max_length=11)
email = models.CharField(max_length=32)
age = models.IntegerField()

在终端执行命令创建该表

注意:1.终端路径在项目名目录下。2.app需要已经注册。

1
2
python manage.py makemigrations
python manage.py migrate
image-20221211191148909
2.删除表

直接将models.py里面的类注释掉即可

1
2
3
4
5
6
7
8
class Userinfo(models.Model):
# name = models.CharField(max_length=32)
# password = models.CharField(max_length=64)
# mobile = models.CharField(max_length=11)
# email = models.CharField(max_length=32)
# age = models.IntegerField()
# docpath = models.CharField(max_length=64, default="")
# imgpath = models.CharField(max_length=64, null=True, blank=True)
3.修改表
  1. 删除字段(直接注释掉)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    #删除imgpath字段
    class Userinfo(models.Model):
    name = models.CharField(max_length=32)
    password = models.CharField(max_length=64)
    mobile = models.CharField(max_length=11)
    email = models.CharField(max_length=32)
    age = models.IntegerField()
    docpath = models.CharField(max_length=64, default="")
    #imgpath = models.CharField(max_length=64, null=True, blank=True)
  2. 修改字段

    1
    2
    #修改max_length属性
    docpath = models.CharField(max_length=128, default="")#将max_length直接改为128
  3. 添加字段

    在表中新建字段(列)时,由于已存在的字段可能已有数据,所以新增列必须要指定新增列对应的数据:

    1. 手动输入一个值(全部行都为输入的值)

    2. 设置默认值

      1
      docpath = models.CharField(default="")
    3. 允许为空

      1
      imgpath = models.CharField(null=True, blank=True)

4.操作表数据

1.添加数据
1
2
3
# ***************添加数据***************
# 本质:insert into app1_userinfo(name,password,mobile,email) values("alleyf","123456","13669156253","alleyf@qq.com")
# Userinfo.objects.create(name="alleyf", password="123456", mobile="13669156253", email="alleyf@qq.com")
1
2
3
4
5
6
7
8
9
10
11
12
13
def register(request):
if request.method == "GET":
# 根据app注册顺序,去每个app目录下的templates中寻找对应的html
return render(request, "register.html")
elif request.method == "POST":
print(request.POST)
username = request.POST.get("name")
password = request.POST.get("pwd")
mobile = request.POST.get("phonenumber")
email = request.POST.get("email")
# 添加用户数据
Userinfo.objects.create(name=username, password=password, mobile=mobile, email=email)
return redirect(reverse("login"))
2.更新数据
1
2
3
4
# 条件更新
Userinfo.objects.filter(id=2).update(password='a123456')
# 全更新
Userinfo.objects.all().update(mobile='13125018525')
3.删除数据
1
2
3
4
# 条件删除
Userinfo.objects.filter(id=2).delete()
# 删除表中全部数据
Userinfo.objects.all().delete()
4.查询数据
1
2
3
4
5
6
7
8
#条件查询
#查询结果不唯一时,返回包含对象的queryset(列表):
userinfo = Userinfo.objects.filter(id=1)
#已知查询结果唯一时利用first()获取第一条数据,返回对象:
userobj = Userinfo.objects.filter(id=1).first()
#全查询
#返回包含对象的列表:
userinfo = Userinfo.objects.all()
1
2
3
4
5
6
7
8
9
def user_list(request):
userlist = []
userinfo = Userinfo.objects.all()
for info in userinfo:
datadic = {'id': info.id, 'name': info.name, 'password': info.password, 'mobile': info.mobile,
'email': info.email}
userlist.append(datadic)
print(userlist)
return render(request, "user_list.html", {'userlist': userlist})

案例:用户管理

要求:

  1. 展示用户列表
    • url路由
    • view函数
      1. 获取用户信息
      2. HTML渲染
  2. 添加用户
    • post请求
    • 添加用户
    • HTML渲染
  3. 修改用户
    • post请求
    • 更新用户信息
  4. 删除用户
    • a标签传递用户id参数get请求
    • 筛选删除指定用户
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
def user(request):
if request.method == 'GET':
nid = request.GET.get('nid')
# 删除用户方法1(get请求)
Userinfo.objects.filter(id=nid).delete()
userlist = []
userinfo = Userinfo.objects.all()
for info in userinfo:
datadic = {'id': info.id, 'name': info.name, 'password': info.password, 'mobile': info.mobile,
'email': info.email}
userlist.append(datadic)
return render(request, "user.html", {'userlist': userlist})
else:
if request.POST['action'] == 'add':
username = request.POST.get("name")
password = request.POST.get("pwd")
mobile = request.POST.get("phonenumber")
email = request.POST.get("email")
# 添加用户数据
Userinfo.objects.create(name=username, password=password, mobile=mobile, email=email)
userinfo = Userinfo.objects.all()
elif request.POST["action"][:6] == "delete":
userid = request.POST["action"][6:]
#删除用户方法2(post请求)
Userinfo.objects.filter(id=userid).delete()
elif request.POST["action"][:4] == "edit":
userid = request.POST["action"][4:]
username = request.POST.get("name")
password = request.POST.get("pwd")
mobile = request.POST.get("phonenumber")
email = request.POST.get("email")
#修改用户
Userinfo.objects.filter(id=userid).update(name=username, password=password, mobile=mobile, email=email)
return redirect(reverse('user'))

11.Django开发

1.主题一:员工管理系统

1.新建项目

预处理:

[![image-20221212135820300](C] \Users\alleyf\AppData\Roaming\Typora\typora-user-images\image-20221212135820300.png)()

2.创建app

方式1终端输入以下命令:

1
python manage.py startapp app名字

方式2打开manage.py任务输入以下命令:

image-20221213133108403
1
startapp   app名

注册app

image-20221213133444596

3.设置表结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
from django.db import models


# Create your models here.
class Department(models.Model):
"""部门表"""
title = models.CharField(verbose_name="标题", max_length=32)

#关联部门表
class UserInfo(models.Model):
"""员工表"""
name = models.CharField(verbose_name="姓名", max_length=16)
password = models.CharField(verbose_name="密码", max_length=16)
age = models.IntegerField(verbose_name="年龄")
account = models.DecimalField(verbose_name="账户余额", max_digits=10, decimal_places=2, default=0)
create_time = models.DateTimeField(verbose_name="入职时间")
# Dejango中对字段值域的约束
gender_choices = (
(1, '男'),
(2, '女'),
)
gender = models.SmallIntegerField(verbose_name='性别', choices=gender_choices)
# 无约束
# depart_id = models.BigIntegerField(verbose_name='部门ID')
# 有约束
# -to:与之关联的表
# -to.field:与之关联的字段
# 1.Django自动
# -将关联字段名添加到被关联的字段的后面(depart_id)
# 2.外键表(部门表)的关联字段被删除
# -2.1级联删除
depart = models.ForeignKey(to='Department', to_field='id', on_delete=models.CASCADE)
# -2.1置空
# depart = models.ForeignKey(to='Department',to_field='id',null=True,blank=True,on_delete=models.SET_NULL)

4.在MySQL中生成表

  • 工具连接MYSQL创建数据库

    1
    create database staffsystem DEFAULT CHARSET utf8 COLLATE utf8_general_ci;
  • 修改配置文件,连接MySQL

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    DATABASES = {
    'default': {
    'ENGINE': 'django.db.backends.mysql',
    'NAME': 'staffsystem', # 数据库名
    'USER': 'root', # 数据库用户名
    'PASSWORD': '123456', # 数据库密码
    'HOST': '127.0.0.1', # 数据库主机地址
    'PORT': 3306, # 数据库连接端口号
    }
    }
  • 执行django命令生成数据表

    1
    2
    3
    在manage.py的task中执行:
    makemigrations
    migrate
    image-20221213142208087

5.创建静态文件和模板文件目录

image-20221213142523883

6.部门管理

体验最原始方法来做。

Django中提供Form和ModelForm组件(方便)。

1.部门列表

重要知识点

==url中传递动态参数==

1
2
#urls.py
path("depart/<int:nid>/edit/", views.depart_edit),
1
2
3
4
5
6
7
8
9
10
11
#views.py
def depart_edit(request, nid):
"""修改部门"""
if request.method == "GET":
# 根据nid获取所要编辑的对象
departobj = models.Department.objects.filter(id=nid).first()
return render(request, "depart_edit.html", {'departobj': departobj})
departdic = request.POST
models.Department.objects.filter(id=nid).update(title=departdic.get('title'), leader=departdic.get('leader'),
number=departdic.get('number'))
return redirect('/depart/list/')
2.新建部门
1
2
3
4
5
6
7
8
def depart_add(request):
"""添加部门"""
if request.method == "GET":
return render(request, "depart_add.html")
departinfo = request.POST
models.Department.objects.create(title=departinfo['title'], leader=departinfo['leader'],
number=departinfo['number'])
return redirect("/depart/list/")
3.修改部门
1
2
3
4
5
6
7
8
9
10
def depart_edit(request, nid):
"""修改部门"""
if request.method == "GET":
# 根据nid获取所要编辑的对象
departobj = models.Department.objects.filter(id=nid).first()
return render(request, "depart_edit.html", {'departobj': departobj})
departdic = request.POST
models.Department.objects.filter(id=nid).update(title=departdic.get('title'), leader=departdic.get('leader'),
number=departdic.get('number'))
return redirect('/depart/list/')
4.删除部门
1
2
3
4
5
def depart_delete(request):
"""删除部门"""
nid = request.GET.get("nid")
models.Department.objects.filter(id=nid).delete()
return redirect("/depart/list/")

7.用户管理

1.用户列表

重要知识点

==用choice约束的字段,获取约束对应值的方法==

1
2
3
4
5
6
# Dejango中对字段值域的约束
gender_choices = (
(1, '男'),
(2, '女'),
)
gender = models.SmallIntegerField(verbose_name='性别', choices=gender_choices)
1
userinfo.get_gender_display()

==外键字段获取外联表中对应的数据==

1
depart = models.ForeignKey(to='Department', to_field='id', on_delete=models.CASCADE)
1
userinfo.depart.title(depart返回的是对象)

==datetime时间转字符串形式==

1
2
#python中转法:( dt.strftime(”%Y-%m-%d %H:%M:%S”))
userinfo.create_time.strftime("%Y-%m-%d %H:%M:%S")
1
2
<!--html的django语法{{ }}转法:-->
userinfo.create_time|date:"Y-m-d H:i:s"
2.新建用户
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def user_add(request):
"""添加用户"""
if request.method == 'GET':
context = {
'gender_choices': models.UserInfo.gender_choices,
'departs': models.Department.objects.all()
}
return render(request, 'user_add.html', context)
name = request.POST.get('name')
pwd = request.POST.get('pwd')
age = request.POST.get('age')
account = request.POST.get('account')
ctime = request.POST.get('ctime')
gender_id = request.POST.get('gender')
depart_id = request.POST.get('depart')
models.UserInfo.objects.create(name=name, password=pwd, age=age, account=account, create_time=ctime,
gender=gender_id, depart_id=depart_id)
return redirect('/user/list/')
3.编辑用户
  • 点击编辑,跳转到编辑页面(将编辑行的ID携带过去)。
  • 编辑页面(默认数据,根据ID获取并设置到页面中)
  • 提交:
    • 错误提示
    • 数据校验
    • 数据库更新
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def user_edit(request, nid):
"""编辑用户"""
# 根据ID获取所要编辑的数据
rowobj = models.UserInfo.objects.filter(id=nid).first()
if request.method == "GET":
# (instance=rowobj)将默认数据显示在表单中
form = UserModelForm(instance=rowobj)
return render(request, 'user_edit.html', {'form': form})
#获取对应用户对象进行数据更新
form = UserModelForm(data=request.POST, instance=rowobj)
if form.is_valid():
# 默认保存的是用户输入的所有数据,如果想要再保存用户输入以外的字段的值
# form.instance.字段名 = 值
form.save()
return redirect('/user/list/')
else:
return render(request, 'user_edit.html', {'form': form})
4.删除用户
1
2
3
def user_delete(request, nid):
models.UserInfo.objects.filter(id=nid).first().delete()
return redirect('/user/list/')

7.模板继承

模板继承可以使父模板的内容复用,子模版直接继承父模板的全部内容并可以覆盖父模板中相应的块。

语法—父模板中:

​ 1.定义父模板中的块block标签

​ 2.标识出哪些在子模版中是允许被修改的

​ 3.block标签:在父模板中定义,可以在子模版中覆盖

1
2
3
{% block block_name %}
父模板可以被覆盖的内容
{% endblock blocl_name%} (**切记一定要写endblock**)

语法—子模版中:

​ 1.继承模板extends标签(写在模板文件的第一行

1
{% entends 'base.html' %}

​ 2.子模版 重写父模板中的内容快

1
2
3
{% block block_name %}
子模版用来覆盖父模板中 block_name 块的内容
{% endblock blocl_name%} (**切记一定要写endblock**)

实例:

  • 父模板
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
{% block title %}
<title>标题</title>
{% endblock %}
<meta name="viewport" content="width=device-width, initial-scale=1.0">
{# <link rel="stylesheet" href="{% static 'css/user.css' %}">#}
<link rel="stylesheet" href="{% static 'plugins/bootstrap-3.4.1/css/bootstrap.min.css' %}">
<link rel="stylesheet" href="{% static 'plugins/fontawesome-free-6.2.1-web/css/fontawesome.min.css' %}">
<style>
* {
padding: 0;
margin: 0;
font-family: 微软雅黑, serif;
letter-spacing: .05em;
}

th {
text-align: center;
}

.navbar {
border-radius: 0;
}
</style>
{% block mystyle %}
{% endblock %}
</head>
<body>
<nav class="navbar navbar-default">
<div class="container">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse"
data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">联通用户管理系统</a>
</div>

<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li class="active"><a href="/depart/list/">部门管理<span class="sr-only">(current)</span></a></li>
<li class=""><a href="/userinfo/list/">用户管理</a></li>
</ul>
<ul class="nav navbar-nav navbar-right">
<li><a href="#">登录</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
aria-expanded="false">Alleyf <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="#">个人资料</a></li>
<li><a href="#">我的信息</a></li>
<li role="separator" class="divider"></li>
<li><a href="#">注销</a></li>
</ul>
</li>
</ul>
</div>
</div>
</nav>
<div>
{% block info %}{% endblock %}
</div>

<script src="https://kit.fontawesome.com/2503dce09a.js" crossorigin="anonymous"></script>
<script src="{% static 'js/jquery-3.6.1.min.js' %}"></script>
<script src="{% static 'plugins/bootstrap-3.4.1/js/bootstrap.min.js' %}"></script>
</body>
  • 子网页
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
{% extends 'layout.html' %}
{% block title %}
<title>部门列表</title>
{% endblock %}
{% block mystyle %}
<style>
</style>
{% endblock %}
{% block info %}
<div class="container">
<div style="margin-bottom: 10px">
<a href="/depart/add/" class="btn btn-primary"><i class="fa fa-plus"></i>新建部门</a>
</div>
<div class="panel panel-info">
<div class="panel-heading"><i class="fa fa-list"></i> 部门列表</div>
<table class="table table-hover table-condensed table-bordered">
<thead>
<tr>
<th>部门ID</th>
<th>部门名称</th>
<th>部门负责人</th>
<th>部门人数</th>
<th>操作</th>
</tr>
</thead>
<tbody class="text-center">
{% for department in departments %}
<tr>
<th scope="row">{{ department.id }}</th>
<td>{{ department.title }}</td>
<td>{{ department.leader }}</td>
<td>{{ department.number }}</td>
<td><a href="/depart/{{ department.id }}/edit/" class="btn btn-info btn-xs"
style="margin-right: 20px">编辑</a><a
href="/depart/delete/?nid={{ department.id }}"
class="btn btn-danger btn-xs">删除</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endblock %}

8.Form和ModelForm

  • 原始方式:不会采用(本质)【麻烦】

    1
    2
    3
    4
    -没有数据校验
    -错误,应该有提示
    -页面上,每个字段都需要我们重新写一遍,数据冗余
    -关联的数据,需要手动获取并循环展示在页面中
  • Django组件

    1. Form组件(较简便)
    2. ModelForm组件(最简便)
8.1Form(常用与非数据库的表单)
1.views.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class UserForm(forms.Form):
name = forms.CharField(widget=forms.TextInput)
pwd = forms.CharField(widget=forms.PasswordInput)
age = forms.IntegerField(widget=forms.TextInput)
account = forms.DecimalField(widget=forms.TextInput)
ctime = forms.DateTimeField(widget=forms.DateTimeField)
gender = forms.CharField(widget=forms.RadioSelect)
depart = forms.CharField(widget=forms.RadioSelect)


def user_add(request):
"""添加用户"""
if request.method == 'GET':
userform = UserForm()
return render(request,'user_add.html',{'userform':userform})
2.user_add.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
-循环法
<form method='post'>
{% for field in userform %}
{{ field }}
{% endfor %}
<!--<input type='text' placeholder='姓名' name='usrname'/>-->
</form>
-手写法
<form method='post'>
{{field.name}}
{{field.pwd}}
{{field.age}}
···
{{field.depart}}
<!--<input type='text' placeholder='姓名' name='usrname'/>-->
</form>
8.2ModelForm(推荐:常用与数据库的表单)
1.models.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
from django import forms
class UserInfo(models.Model):
"""员工表"""
name = models.CharField(verbose_name="姓名", max_length=16)
password = models.CharField(verbose_name="密码", max_length=16)
age = models.IntegerField(verbose_name="年龄")
account = models.DecimalField(verbose_name="账户余额", max_digits=10, decimal_places=2, default=0)
create_time = models.DateTimeField(verbose_name="入职时间")
gender_choices = (
(1, '男'),
(2, '女'),
)
gender = models.SmallIntegerField(verbose_name='性别', choices=gender_choices)
depart = models.ForeignKey(to='Department', to_field='id', on_delete=models.CASCADE)
2.views.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class UserForm(forms.ModelForm):
# 自定义的字段
xxx = forms.CharField(widget=forms.TextInput)

# 数据库中的字段
class Meta:
model = models.UserInfo
fields = ["name", "password", "age", "gender", "depart", "xxx"]


def user_add(request):
"""添加用户"""
if request.method == 'GET':
userform = UserForm()
return render(request,'user_add.html',{'userform':userform})
3.user_add.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
-循环法
<form method='post'>
{% for field in userform %}
{{ item.label }}:{{ item }}
{% endfor %}
<!--<input type='text' placeholder='姓名' name='usrname'/>-->
</form>
-手写法
<form method='post'>
{{field.name}}
{{field.pwd}}
{{field.age}}
···
{{field.depart}}
<!--<input type='text' placeholder='姓名' name='usrname'/>-->
</form>

示例:

  1. views.py

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    class UserModelForm(forms.ModelForm):
    name = forms.CharField(label="用户名", min_length=1)

    # 数据库中的字段
    class Meta:
    model = models.UserInfo
    fields = ["name", "password", "age", "account", "create_time", "gender", "depart"]

    widgets = {
    "name": forms.TextInput(attrs={"class": "form-control input"}),
    # "password": forms.PasswordInput(attrs={"class": "form-control input"}),
    # "age": forms.TextInput(attrs={"class": "form-control input"}),
    # "account": forms.TextInput(attrs={"class": "form-control input"}),
    "create_time": forms.DateTimeInput(attrs={"class": " form-control input", "type": "datetime-local"}),
    # "gender": forms.Select(attrs={"class": "form-control input"}),
    # "depart": forms.Select(attrs={"class": "form-control input"}),
    }

    def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)
    # 循环找到所有的字段,给其添加样式
    for name, field in self.fields.items():
    field.widget.attrs = {"class": "input form-control", "placeholder": field.label}



    def user_modelform_add(request):
    """添加用户modelform版"""
    if request.method == 'GET':
    form = UserModelForm()
    return render(request, 'user_modelform_add.html', {'form': form})
    # 用户提交数据,数据校验
    form = UserModelForm(data=request.POST)
    if form.is_valid():
    # 如果数据合法,则保存数据并添加到表中
    form.save()
    return redirect('/user/list/')
    else:
    return render(request, 'user_modelform_add.html', {'form': form})
  2. user_modelform_add.html

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    {% extends 'user_list.html' %} # 继承父模块的标识
    {% block title %}
    <title>新建用户</title>
    {% endblock %}
    {% block mystyle %}
    <style>
    .input {
    display: inline-block;
    margin: 10px auto;
    min-height: 50px;
    width: 300px;
    padding: 0 1rem;
    color: #1e2732;
    font-size: 15px;
    border: 1px solid #5e4dcd;
    border-radius: 6px;
    background-color: transparent;
    }

    .button--submit {
    display: block;
    margin: 10px auto;
    min-height: 50px;
    padding: .5em 1em;
    border: none;
    border-radius: 6px;
    background-color: #5e4dcd;
    color: #fff;
    font-size: 15px;
    cursor: pointer;
    transition: background-color .3s ease-in-out;
    }

    .button--submit:hover {
    background-color: #5e5dcd;
    }

    .input:focus, .input:focus-visible {
    border-color: #3898EC;
    outline: none;
    }
    </style>
    {% endblock %}
    {% block info %}
    <div>
    <div class="container">
    <div class="panel panel-info">
    {% block actiontitle %}
    <div class="panel-heading">新建用户</div>
    {% endblock %}
    <div class="panel-body">
    {% block userform %}
    <form class="input-group" method="post" novalidate>
    {% csrf_token %}
    {% for item in form %}
    <div class="form-group col-md-6">
    <label>{{ item.label }}</label>
    {{ item }}
    <span style="color: #c12c1f"><strong>{{ item.errors.0 }}</strong></span>
    </div>
    {% endfor %}
    <div class="form-group col-md-6">
    <input class="button--submit " value="Subscribe" type="submit">
    </div>
    </form>
    {% endblock %}
    </div>
    </div>
    </div>
    </div>
    {% endblock %}

在配置文件中可以设置语言种类

1
2
# LANGUAGE_CODE = "en-us" 英文
LANGUAGE_CODE = "zh-hans" 中文

2.主题二:靓号管理(数据校验)

1.表结构设计

id mobile price lever(choices) status(1未注册/2已注册)
1 xxx xxx xxx xxx
2 xxx xxx xxx xxx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class PrettyNum(models.Model):
"""靓号表"""
moblie = models.CharField(verbose_name='手机号', max_length=11) # 存为字符串便于正则表达式搜索
price = models.IntegerField(verbose_name='价格')
level_choices = (
(1, "一级"),
(2, "二级"),
(3, "三级"),
(4, "四级"),
(5, "五级"),
)
level = models.SmallIntegerField(verbose_name="星级", choices=level_choices, default=1)
status_choices = (
(1, '已注册'),
(2, '未注册')
)
status = models.SmallIntegerField(verbose_name='状态', choices=status_choices, default=2)

2.靓号列表

  • url
  • 函数
    • 获取所有靓号
    • 结合html+render展示靓号
1
2
3
4
def phone_list(request):
# 按照级别降序排序(select * from 表 order by lever desc
phonenum = models.PrettyNum.objects.all().order_by('-level')
return render(request, 'phone_list.html', {'phonenum': phonenum})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
{% extends 'layout.html' %}
{% block title %}
<title>靓号列表</title>
{% endblock %}
{% block mystyle %}
{% endblock %}
{% block info %}
<div class="container">
<div style="margin-bottom: 10px">
<a href="/phone/add/" class="btn btn-primary"><i class="fa fa-plus"></i>新建靓号</a>
</div>
<div class="panel panel-info">
<div class="panel-heading"><i class="fa fa-list"></i> 靓号列表</div>
<table class="table table-hover table-condensed table-bordered">
<thead>
<tr>
<th>ID</th>
<th>号码</th>
<th>价格</th>
<th>星级</th>
<th>状态</th>
<th>操作</th>
</tr>
</thead>
<tbody class="text-center">
{% for pninfo in phonenum %}
<tr>
<th scope="row">{{ pninfo.id }}</th>
<td>{{ pninfo.moblie }}</td>
<td>{{ pninfo.price }}</td>
<td>{{ pninfo.get_level_display }}</td>
<td>{{ pninfo.get_status_display }}</td>
<td><a href="/phone/{{ pninfo.id }}/edit/" class="btn btn-info btn-xs">编辑</a><a
href="/phone/{{ pninfo.id }}/delete/"
class="btn btn-danger btn-xs">删除</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endblock %}

3.新建靓号

  • 列表点击跳转:/phone/add/
  • url
  • ModelForm类
  • 函数
    • 实例化类对象
    • 通过render将对象传入html中
    • 模板循环展示所有字段
    • 处理提交数据,数据验证
    • 数据保存
    • 重定向回数据展示页面
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
class PhoneModelForm(forms.ModelForm):
# 验证:方式1(字段+正则)
# pnumber = forms.CharField(
# label="号码",
# # 正则表达式校验格式
# validators=[RegexValidator(r'^1[3-9]\d{9}$', '手机号格式错误')],
# )

class Meta:
model = models.PrettyNum
# fields = "__all__" 展示所有字段
fields = ["moblie", "price", "level", "status"]
# exclude = ["字段名"] 排除某个字段

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# 循环找到所有的字段,给其添加样式
for name, field in self.fields.items():
field.widget.attrs = {"class": "input form-control", "placeholder": field.label}

# 验证:方式2(钩子方法)
def clean_moblie(self):
txt_mobile = self.cleaned_data["moblie"]
if len(txt_mobile) != 11:
# 验证不通过抛出异常
raise ValidationError("格式错误")
# 验证通过,返回用户输入值
# return什么数据库到时候保存的就是什么值
return txt_mobile

def phone_add(request):
if request.method == 'GET':
form = PhoneModelForm()
return render(request, 'phone_add.html', {'form': form})
form = PhoneModelForm(data=request.POST)
if form.is_valid():
form.save()
return redirect('/phone/list/')
return render(request, 'phone_add.html', {'form': form})

==字段验证==

image-20221214130011283

不允许手机号重复

  • 添加:
1
2
3
4
5
6
7
8
9
10
def clean_moblie(self):
txt_mobile = self.cleaned_data["moblie"]
exist = models.PrettyNum.objects.filter(moblie=txt_mobile).exists()
if exist:
raise ValidationError("手机号已存在")
elif len(txt_mobile) != 11:
# 验证不通过抛出异常
raise ValidationError("格式错误")
# 验证通过,返回用户输入值
return txt_mobile
  • 编辑:
1
2
3
4
5
6
7
8
9
10
11
exclude(self.instance.pk)排出自己以外,其他的数据是否和提交的手机号重复
def clean_moblie(self):
txt_mobile = self.cleaned_data["moblie"]
exist = models.PrettyNum.objects.filter(moblie=txt_mobile).exclude(id=self.instance.pk).exists()
if exist:
raise ValidationError("手机号已存在")
elif len(txt_mobile) != 11:
# 验证不通过抛出异常
raise ValidationError("格式错误")
# 验证通过,返回用户输入值
return txt_mobile

4.编辑靓号

  • 列表页面:/phone/数字/edit/

  • url中传递参数<int:nid>

  • 函数

    • 根据ID获取当前编辑的对象
    • ModelForm配合,默认显示数据
    • 提交修改
1
2
3
4
5
6
7
8
9
10
11
def phone_edit(request, nid):
"""编辑靓号"""
rowobj = models.PrettyNum.objects.filter(id=nid).first()
if request.method == 'GET':
form = EditPhoneModelForm(instance=rowobj)
return render(request, 'phone_edit.html', {'form': form})
form = EditPhoneModelForm(data=request.POST, instance=rowobj)
if form.is_valid():
form.save()
return redirect('/phone/list/')
return render(request, 'phone_edit.html', {'form': form})

5.删除靓号

1
2
3
4
def phone_delete(request, nid):
"""删除靓号"""
models.PrettyNum.objects.filter(id=nid).first().delete()
return redirect('/phone/list/')

6.搜索靓号

1
2
3
4
models.PhoneNum.objects.filter(mobile="13771966523"id=2)

search_dict = {"mobile":"13771966523""id":2}
models.PhoneNum.objects.filter(**search_dict)

查询条件

1
2
3
4
5
6
7
8
9
10
#数字条件
models.PhoneNum.objects.filter(id=2) #等于2
models.PhoneNum.objects.filter(id__gt=2) #大于2
models.PhoneNum.objects.filter(id__gt=2) #大于2
models.PhoneNum.objects.filter(id__gte=2)#大于等于2
models.PhoneNum.objects.filter(id__lt=2) #小于2
models.PhoneNum.objects.filter(id__lte=2)#小于等于2

search_dict = {"id__gt":2}
models.PhoneNum.objects.filter(**search_dict)
1
2
3
4
5
6
7
8
#字符串条件
models.PhoneNum.objects.filter(mobile="137") #等于137
models.PhoneNum.objects.filter(mobile__startswith="137") #以137开头
models.PhoneNum.objects.filter(mobile__endswith="137") #以137结尾
models.PhoneNum.objects.filter(mobile__contains="137") #包含有137

search_dict = {"mobile__startswith":"137"}
models.PhoneNum.objects.filter(**search_dict)

示例:

1
2
3
4
5
6
7
8
9
def phone_list(request):
"""靓号列表"""
search_dict = {'mobile__contains': ""}
res = request.GET.get("m", default='')
if res:
search_dict['mobile__contains'] = res
# 按照级别降序排序(select * from 表 order by lever desc
phonenum = models.PrettyNum.objects.filter(**search_dict).order_by('-level')
return render(request, 'phone_list.html', {'phonenum': phonenum, 'res': res})
1
2
3
4
5
6
7
8
9
10
11
12
13
<div style="margin-bottom: 10px" class="clearfix">
<a href="/phone/add/" class="btn btn-primary"><i class="fa fa-plus"></i>新建靓号</a>
<div style="float: right;width: 300px">
<form method="get">
<div class="input-group">
<input type="text" name="m" placeholder="Search for ···" class="form-control" value={{ res }}>
<span class="input-group-btn">
<button class="btn btn-default"><i class="fa fa-search"></i> </button>
</span>
</div>
</form>
</div>
</div>

7.分页

1
queryset = models.PhoneNum.objects.all()[:10]	#取搜索到的前十条数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
"""-------------------------------------view.py-------------------------------------"""
def phone_list(request):
""" 靓号列表 """
# 号码参数初始化
search_dict = {}
# 获取号码搜索参数
search_data = request.GET.get(key="m", default='')
if search_data:
search_dict['mobile__contains'] = search_data
# 页码参数初始化
pagesize = 10
pageplus = 5
queryset = models.PrettyNum.objects.filter(**search_dict).order_by('-level')
# 获取当前页面对象
page_obj = pagination.Pagination(request, query_set=queryset, page_size=pagesize, page_plus=pageplus)
# 获取页面数据
page_queryset = page_obj.page_queryset
# 获取html信息
# 方法一:获取django模板信息
# pagels, pageinfo = page_obj.djangotemplateinfo()
# context = {
# 'page_queryset': page_queryset,
# 'search_data': search_data,
# 'pagels': pagels,
# 'pageinfo': pageinfo
# }
# return render(request, 'phone_list.html',context)
# 方法二:获取html字符串
page_str = page_obj.htmlstr()
context = {
'page_queryset': page_queryset,
'search_data': search_data,
'page_str': page_str
}
return render(request, 'phone_list.html', context)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
"""-------------------------------------前端页面-------------------------------------"""
"""
<div class="text-center">
<ul class="pagination pagination-xs">
{# 方法二对应的分页展示方法#}
{{ page_str }}
{# 方法一对应的分页展示方法#}
{# <li>#}
{# <a href="?page={{ pageinfo.lpage }}&&m={{ search_data }}"><i class="fa fa-less-than"></i></a>#}
{# </li>#}
{# {% for page in pagels %}#}
{# {% if page != pageinfo.nowpage %}#}
{# <li>#}
{# <a href="?page={{ page }}&&m={{ search_data }}">{{ page }}</a>#}
{# </li>#}
{# {% else %}#}
{# <li class="active">#}
{# <a href="?page={{ page }}&&m={{ search_data }}">{{ page }}</a>#}
{# </li>#}
{# {% endif %}#}
{# {% endfor %}#}
{# <li>#}
{# <a href="?page={{ pageinfo.npage }}&&m={{ search_data }}"><i class="fa fa-greater-than"></i></a>#}
{# </li>#}
{# <li style="width: 150px;float: right">#}
{# <form method="get">#}
{# <div class="input-group">#}
{# <input type="text" name="page"#}
{# placeholder="Search for ···"#}
{# class="form-control"#}
{# value={{ pageinfo.nowpage }}>#}
{# <span class="input-group-btn">#}
{# <button class="btn btn-default"><i class=" fa-brands fa-airbnb"></i> </button>#}
{# </span>#}
{# </div>#}
{# </form>#}
{# </li>#}
</ul>
</div>
"""

3.个人自定义组件

3.1分页组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
"""--------------------------------------自定义分页组件类------------------------------------"""
"""-----------------------------------------信息栏------------------------------------------"""
"""datetime: 2022-12-15 1:13"""
"""author: Alleyf"""
"""email: alleyf@qq.com"""
"""-------------------------------------view.py使用教程-------------------------------------"""
"""
def phone_list(request):
# 1.搜索参数初始化
search_dict = {}
# 获取号码搜索参数
search_data = request.GET.get(key="m", default='')
if search_data:
search_dict['mobile__contains'] = search_data
# 2.页码参数初始化
pagesize = 10
pageplus = 5
# 3.筛选符合条件的数据
queryset = models.PrettyNum.objects.filter(**search_dict).order_by('-level')
# 4.实例化页面对象
page_obj = pagination.Pagination(request, query_set=queryset, page_size=pagesize, page_plus=pageplus)
# 5.获取页面数据
page_queryset = page_obj.page_queryset
# 6.获取分页展示所需的信息
# 6.1方法一:获取django模板信息
# pagels, pageinfo = page_obj.djangotemplateinfo()
# context = {
# 页面数据信息
# 'page_queryset': page_queryset,
# 搜索参数
# 'search_data': search_data,
# 页码标号
# 'pagels': pagels,
# 当前及前后页信息
# 'pageinfo': pageinfo
# }
# return render(request, 'phone_list.html',context)
# 6.2方法二:获取html字符串
page_str = page_obj.htmlstr()
context = {
# 页面数据信息
'page_queryset': page_queryset,
# 搜索参数
'search_data': search_data,
# 分页html字符串组件
'page_str': page_str
}
return render(request, 'phone_list.html', context)
"""
"""-------------------------------------前端页面使用教程-------------------------------------"""
"""
<div class="text-center">
<ul class="pagination pagination-xs">
{# 方法二对应的分页展示方法#}
{{ page_str }}
{# 方法一对应的分页展示方法#}
{# <li>#}
{# <a href="?page={{ pageinfo.lpage }}&&m={{ search_data }}"><i class="fa fa-less-than"></i></a>#}
{# </li>#}
{# {% for page in pagels %}#}
{# {% if page != pageinfo.nowpage %}#}
{# <li>#}
{# <a href="?page={{ page }}&&m={{ search_data }}">{{ page }}</a>#}
{# </li>#}
{# {% else %}#}
{# <li class="active">#}
{# <a href="?page={{ page }}&&m={{ search_data }}">{{ page }}</a>#}
{# </li>#}
{# {% endif %}#}
{# {% endfor %}#}
{# <li>#}
{# <a href="?page={{ pageinfo.npage }}&&m={{ search_data }}"><i class="fa fa-greater-than"></i></a>#}
{# </li>#}
{# <li style="width: 150px;float: right">#}
{# <form method="get">#}
{# <div class="input-group">#}
{# <input type="text" name="page"#}
{# placeholder="Search for ···"#}
{# class="form-control"#}
{# value={{ pageinfo.nowpage }}>#}
{# <span class="input-group-btn">#}
{# <button class="btn btn-default"><i class=" fa-brands fa-airbnb"></i> </button>#}
{# </span>#}
{# </div>#}
{# </form>#}
{# </li>#}
</ul>
</div>
"""
"""----------------------------------------分页类定义---------------------------------------"""
from django.utils.safestring import mark_safe # 确保html字符串安全
import copy # 深拷贝


class Pagination(object):
"""构造函数"""

def __init__(self, request, query_set, page_size=10, page_param='page', page_plus=2):
"""
:param request: 请求的对象
:param query_set: 符合条件的查询的数据
:param page_size: 每页展示的数据量
:param page_param: 在url中获取分页参数 eg:/phone/list/?page=10
:param page_plus: 显示当前页的前后几页(页码)
"""
page = request.GET.get(key=page_param, default="1")
if page.isdecimal():
page = int(page)
else:
page = 1
query_dict = copy.deepcopy(request.GET)
query_dict._mutable = True
self.query_dict = query_dict # url的get参数
self.page = page
self.page_size = page_size
self.page_param = page_param
self.page_plus = page_plus
self.start = (page - 1) * page_size
self.end = page * page_size
self.page_queryset = query_set[self.start:self.end]
self.total_cnt = query_set.count()
total_page_cnt, remainder = divmod(self.total_cnt, page_size)
if remainder:
total_page_cnt += 1
self.total_page_cnt = total_page_cnt

"""方法1:Django模板法"""

def djangotemplateinfo(self):
# 显示当前页的前两页和后两页页码增量为2
pagels = []
pagestart = self.page - self.page_plus
pageend = self.page + self.page_plus
# 若总页数小于5时
if self.total_page_cnt < 5:
pagestart = 1
pageend = self.total_page_cnt
# 若总页数大于等于5
else:
# 若当前页小于等于页码增量
if self.page <= self.page_plus:
pagestart = 1
pageend = 2 * self.page_plus + 1
# 若当前页尾大于总页数
elif pageend > self.total_page_cnt:
pagestart -= self.page_plus
pageend = self.total_page_cnt
# 正常情况下
else:
pagestart = self.page - self.page_plus
pageend = self.page + self.page_plus
# 生成页码标号
for i in range(pagestart, pageend + 1):
pagels.append(i)
# 当前页和其前后页信息
pageinfo = {'nowpage': self.page, 'lpage': 1 if self.page <= 2 else self.page - 1,
'npage': pageend if self.page + 1 > pageend else self.page + 1, 'total_page': self.total_page_cnt}
return pagels, pageinfo

"""方法2:HTML字符串法"""

def htmlstr(self):
# 显示当前页的前两页和后两页页码增量为2
self.start = self.page - self.page_plus
self.end = self.page + self.page_plus
# 若总页数小于5时
if self.total_page_cnt < 5:
self.start = 1
self.end = self.total_page_cnt
# 若总页数大于等于5
else:
# 若当前页小于等于页码增量
if self.page <= self.page_plus:
self.start = 1
self.end = 2 * self.page_plus + 1
# 若当前页尾大于总页数
elif self.end > self.total_page_cnt:
self.start -= self.page_plus
self.end = self.total_page_cnt
# 正常情况下
else:
self.start = self.page - self.page_plus
self.end = self.page + self.page_plus

# 生成页码
page_str_ls = []
# 首页
self.query_dict.setlist(self.page_param, [1])
page_str_ls.append('<li><a href="?{}">首页</a></li>'.format(self.query_dict.urlencode()))
# 上一页
self.query_dict.setlist(self.page_param, [self.page - 1])
if self.page > 1:
prev = '<li><a href="?{}"><i class="fa fa-less-than"></i></a></li>'.format(self.query_dict.urlencode())
else:
self.query_dict.setlist(self.page_param, [1])
prev = '<li><a href="?{}"><i class="fa fa-less-than"></i></a></li>'.format(self.query_dict.urlencode())
page_str_ls.append(prev)
# 页面
for i in range(self.start, self.end + 1):
self.query_dict.setlist(self.page_param, [i])
if i == self.page:
ele = '<li class="active"><a href="?{}">{}</a></li>'.format(self.query_dict.urlencode(), i)
else:
ele = '<li><a href="?{}">{}</a></li>'.format(self.query_dict.urlencode(), i)
page_str_ls.append(ele)
# 下一页
self.query_dict.setlist(self.page_param, [self.page + 1])
if self.page < self.total_page_cnt:
nxt = '<li><a href="?{}"><i class="fa fa-greater-than"></i></a></li>'.format(self.query_dict.urlencode())
else:
self.query_dict.setlist(self.page_param, [self.total_page_cnt])
nxt = '<li><a href="?{}"><i class="fa fa-greater-than"></i></a></li>'.format(self.query_dict.urlencode())
page_str_ls.append(nxt)
# 尾页
self.query_dict.setlist(self.page_param, [self.total_page_cnt])
page_str_ls.append('<li><a href="?{}">尾页</a></li>'.format(self.query_dict.urlencode()))
search_string = """
<li style="width: 150px;float: right">
<form method="get">
<div class="input-group">
<input type="text" name="page"
placeholder="Page"
class="form-control"
value={}>
<span class="input-group-btn">
<button class="btn btn-default"><i class=" fa-brands fa-airbnb"></i> </button>
</span>
</div>
</form>
</li>
""".format(self.page)
page_str_ls.append(search_string)
page_str = mark_safe("".join(page_str_ls))
return page_str


"""----------------------------------------分割结束符---------------------------------------"""

3.2时间插件

  • 前端引入js和css

    1
    2
    3
    4
    <link rel="stylesheet"
    href="{% static 'plugins/bootstrap-datetimepicker-master/css/bootstrap-datetimepicker.min.css' %}">

    <script src="{% static 'plugins/bootstrap-datetimepicker-master/js/bootstrap-datetimepicker.min.js' %}"></script>
  • ModelForm表单类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    class InfoModelForm(forms.ModelForm):
    # 数据库中的字段
    class Meta:
    #模型设置为数据表模型
    model = models.Info
    fields = ["create_time"]
    #插件(可设置属性)
    #设置类型为datetime-local
    widgets = {
    "create_time": forms.DateTimeInput(attrs={"class": " form-control input", "type": "datetime-local"}),
    }

    def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)
    # 循环找到所有的字段,给其添加样式
    for name, field in self.fields.items():
    field.widget.attrs = {"class": "input form-control", "placeholder": field.label}

4.ModelForm和BootStrap

ModelForm可以帮助我们生成html标签

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
class PhoneModelForm(forms.ModelForm):
# 验证:方式1
# pnumber = forms.CharField(
# label="号码",
# # 正则表达式校验格式
# validators=[RegexValidator(r'^1[3-9]\d{9}$', '手机号格式错误')],
# )

class Meta:
model = models.PrettyNum
# fields = "__all__" 展示所有字段
fields = ["mobile", "price", "level", "status"]
# exclude = ["字段名"] 排除某个字段

#插件
# 1.单独设置样式:id设置为IDmobile
widgets = {
"mobile": forms.TextInput(attrs={"class": " form-control input", "id": "IDmobile"}),
}
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# 2.批量设置样式:循环找到所有的字段,给其添加相同样式
for name, field in self.fields.items():
# 有责修改样式
if field.widget.attrs:
field.widget.attrs["class"] = "form-control"
field.widget.attrs["placeholder"] = field.label
# 无责添加样式
else:
field.widget.attrs = {"class": "input form-control", "placeholder": field.label}

# 验证:方式2(钩子方法)
def clean_mobile(self):
txt_mobile = self.cleaned_data["mobile"]
exist = models.PrettyNum.objects.filter(mobile=txt_mobile).exists()
if exist:
raise ValidationError("手机号已存在")
elif len(txt_mobile) != 11:
# 验证不通过抛出异常
raise ValidationError("格式错误")
# 验证通过,返回用户输入值
return txt_mobile
form = PhoneModelForm()
1
2
3
4
{{form.mobile}}
{{form.price}}
{{form.level}}
{{form.status}}

1.自定义表单标签类

==日期必须重设样式==

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from django import forms


class BootStrapModelForm(forms.ModelForm):

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# 2.批量设置样式:循环找到所有的字段,给其添加相同样式
for name, field in self.fields.items():
# 有责修改样式
if field.widget.attrs:
field.widget.attrs["class"] = "input form-control"
field.widget.attrs["placeholder"] = field.label
# 无责添加样式
else:
field.widget.attrs = {"class": "input form-control", "placeholder": field.label}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class PhoneModelForm(BootStrapModelForm):
# 验证:方式1
# pnumber = forms.CharField(
# label="号码",
# # 正则表达式校验格式
# validators=[RegexValidator(r'^1[3-9]\d{9}$', '手机号格式错误')],
# )
class Meta:
model = models.PrettyNum
# fields = "__all__" 展示所有字段
fields = ["mobile", "price", "level", "status"]
# exclude = ["字段名"] 排除某个字段
#插件
# 1.单独设置样式:id设置为IDmobile,日期必须重设样式
widgets = {
"mobile": forms.TextInput(attrs={"class": " form-control input", "id": "IDmobile"}),
"create_time": forms.DateTimeInput(attrs={"class": " form-control input", "type": "datetime-local"})
}
# 验证:方式2(钩子方法)
def clean_mobile(self):
txt_mobile = self.cleaned_data["mobile"]
exist = models.PrettyNum.objects.filter(mobile=txt_mobile).exists()
if exist:
raise ValidationError("手机号已存在")
elif len(txt_mobile) != 11:
# 验证不通过抛出异常
raise ValidationError("格式错误")
# 验证通过,返回用户输入值
return txt_mobile

5.管理员操作

1.管理员列表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#utils/form.py
class AdminModelForm(bootstrapmodelform.BootStrapModelForm):
confirm_password = forms.fields.CharField(
label="确认密码",
max_length=64,
# render_value=True使校验失败后值不被清空
widget=forms.PasswordInput(render_value=True),
# 正则表达式校验格式
validators=[RegexValidator(r'^[\w]{6,16}$', '6~16位,包含大小写字母和数字的组合')],
)

class Meta:
model = models.Admin
fields = ["username", "password", "confirm_password"]
widgets = {"password": forms.PasswordInput(attrs={"class": "form-control input"}, render_value=True)}

# 验证用户名是否已存在
def clean_username(self):
username = self.cleaned_data["username"]
exist = models.Admin.objects.filter(username=username).exists()
if exist:
raise ValidationError("用户名已存在")
# return什么数据库到时候保存的就是什么值
return username

# 对密码进行md5加密
def clean_password(self):
pwd = self.cleaned_data["password"]
return md5(pwd)

# 验证密码是否一致
def clean_confirm_password(self):
password = self.cleaned_data["password"]
confirm = md5(self.cleaned_data["confirm_password"])
if confirm != password:
raise ValidationError("密码不一致")
return confirm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#views/admin.py
from django.shortcuts import render, redirect

from staffsys import models
from staffsys.utils import pagination
from staffsys.utils.form import AdminModelForm, RstModelForm


def admin_list(request):
"""管理员列表"""
# 参数初始化
search_dict = {}
# 获取管理员搜索参数
search_data = request.GET.get(key="u", default='')
if search_data:
search_dict['username__contains'] = search_data
queryset = models.Admin.objects.filter(**search_dict).order_by('id')
# 获取当前页面对象
page_obj = pagination.Pagination(request, query_set=queryset)
# 获取页面数据
page_queryset = page_obj.page_queryset
page_str = page_obj.htmlstr()
context = {
"queryset": page_queryset,
'search_data': search_data,
"page_str": page_str
}
return render(request, "admin_list.html", context)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
admin_list.html
{% extends 'layout.html' %}
{% block mytitle %}
<title>管理员列表</title>
{% endblock %}
{% block mystyle %}
{% endblock %}
{% block info %}
<div class="container">
<div style="margin-bottom: 10px" class="clearfix">
<a href="/admin/add/" class="btn btn-primary"><i class="fa fa-plus"></i>新建管理员</a>
<div style="float: right;width: 300px">
<form method="get">
<div class="input-group">
<input type="text" name="u" placeholder="Search for username" class="form-control"
value={{ search_data }}>
<span class="input-group-btn">
<button class="btn btn-default"><i class="fa fa-search"></i> </button>
</span>
</div>
</form>
</div>
</div>
<div class="panel panel-info">
<div class="panel-heading"><i class="fa fa-list"></i>管理员列表</div>
<table class="table table-hover table-condensed table-bordered">
<thead>
<tr>
<th>ID</th>
<th>用户名</th>
<th>密码</th>
<th>重置密码</th>
<th>操作</th>
</tr>
</thead>
<tbody class="text-center">
{% for admin in queryset %}
<tr>
<th scope="row">{{ admin.id }}</th>
<td>{{ admin.username }}</td>
<td>{{ admin.password }}</td>
<td><a href="/admin/{{ admin.id }}/reset/">重置密码</a></td>
<td><a href="/admin/{{ admin.id }}/edit/" class="btn btn-info btn-xs">编辑</a><a
href="/admin/{{ admin.id }}/delete/"
class="btn btn-danger btn-xs">删除</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<div class="text-center">
<ul class="pagination pagination-xs">
{{ page_str }}
</ul>
</div>
</div>
{% endblock %}

2.添加管理员

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#views/admin.py
def admin_add(request):
title = "新建管理员"
if request.method == "GET":
form = AdminModelForm()
context = {
'title': title,
'form': form
}
return render(request, "change.html", context)
form = AdminModelForm(data=request.POST)
context = {
'title': title,
'form': form
}
if form.is_valid():
form.save()
return redirect('/admin/list/')
else:
return render(request, "change.html", context)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
change.html
{% extends 'layout.html' %} # 继承父模块的标识
{% block mytitle %}
<title>{{ title }}</title>
{% endblock %}
{% block mystyle %}
<style>
.input {
display: inline-block;
margin: 10px auto;
min-height: 50px;
width: 300px;
padding: 0 1rem;
color: #1e2732;
font-size: 15px;
border: 1px solid #5e4dcd;
border-radius: 6px;
background-color: transparent;
}

.button--submit {
display: block;
margin: 10px auto;
min-height: 50px;
padding: .5em 1em;
border: none;
border-radius: 6px;
background-color: #5e4dcd;
color: #fff;
font-size: 15px;
cursor: pointer;
transition: background-color .3s ease-in-out;
}

.button--submit:hover {
background-color: #5e5dcd;
}

.input:focus, .input:focus-visible {
border-color: #3898EC;
outline: none;
}
</style>
{% endblock %}
{% block info %}
<div>
<div class="container">
<div class="panel panel-info">
{% block actiontitle %}
<div class="panel-heading">{{ title }}</div>
{% endblock %}
<div class="panel-body">
{% block myform %}
<form class="input-group col-md-12" method="post" novalidate>
{% csrf_token %}
{% for item in form %}
<div class="form-group col-md-6">
<label>{{ item.label }}</label>
{{ item }}
<span style="color: #c12c1f"><strong>{{ item.errors.0 }}</strong></span>
</div>
{% endfor %}
<div class="form-group col-md-6">
<input class="button--submit " value="Subscribe" type="submit">
</div>
</form>
{% endblock %}
</div>
</div>
</div>
</div>
{% endblock %}

3.编辑管理员

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#/views/admin.py
def admin_edit(request, nid):
"""编辑管理员"""
title = "编辑管理员"
rowobj = models.Admin.objects.filter(id=nid).first()
if request.method == "GET":
if rowobj:
form = AdminModelForm(instance=rowobj)
context = {
"title": title,
"form": form
}
return render(request, "change.html", context)
else:
return redirect("/admin/list/")
form = AdminModelForm(data=request.POST, instance=rowobj)
context = {
"title": title,
"form": form
}
if form.is_valid():
form.save()
return redirect("/admin/list/")
else:
return render(request, "change.html", context)

==change.html同上==

4.删除管理员

1
2
3
4
5
6
#/views/admin.py
def admin_delete(request, nid):
"""删除管理员"""
models.Admin.objects.filter(id=nid).first().delete()
return redirect("/admin/list/")

5.重置密码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#/views/admin.py
def admin_reset(request, nid):
"""重置密码"""
rowobj = models.Admin.objects.filter(id=nid).first()
title = "重置密码-{}".format(rowobj.username)
if rowobj:
if request.method == "GET":
form = RstModelForm()
context = {
"title": title,
"form": form
}
return render(request, "change.html", context)
form = RstModelForm(data=request.POST, instance=rowobj)
context = {
"title": title,
"form": form
}
if form.is_valid():
form.save()
return redirect("/admin/list/")
return render(request, "change.html", context)
else:
return redirect("/admin/list/")

6.用户登录

什么事cookie和session?

用户发起请求时浏览器会产生一个cookie(sessionid)(随机字符串)里面包含用户的信息,该cookie会存储在用户浏览器中,而服务端也会存储该cookie(session_key),并且存储该用户的session信息,以此来区别不同用户并且实现有状态长连接

  • https://fcsy.fit
    http://fcsy.fit
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37

    **http请求为无状态&&短连接**

    #### **form.py**

    ```py
    class LoginForm(forms.Form):
    """登录表单"""
    username = forms.CharField(
    label="用户名",
    max_length=32,
    widget=forms.TextInput,
    required=True,
    )
    password = forms.CharField(
    label="密码",
    max_length=64,
    widget=forms.PasswordInput(render_value=True),
    required=True,
    )

    def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)
    # 2.批量设置样式:循环找到所有的字段,给其添加相同样式
    for name, field in self.fields.items():
    # 有责修改样式
    if field.widget.attrs:
    field.widget.attrs["class"] = "input-item"
    field.widget.attrs["placeholder"] = field.label

    # 无责添加样式
    else:
    field.widget.attrs = {"class": "input-item", "placeholder": field.label}

    def clean_password(self):
    pwd = self.cleaned_data.get("password")
    return md5(pwd)

==cookie和session==

实现对用户信息的保存

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from django.shortcuts import render, redirect
from staffsys.utils.form import LoginForm
from staffsys.models import Admin


def login(request):
if request.method == "GET":
form = LoginForm()
return render(request, "login.html", {'form': form})
form = LoginForm(data=request.POST)
if form.is_valid():
# 去数据库校验用户名和密码是否存在且正确
usrobj = Admin.objects.filter(**form.cleaned_data).first()
if usrobj:
# 用户名和密码正确
# 构建session信息
request.session["info"] = {"id": usrobj.id, "name": usrobj.username}
return redirect("/admin/list/")
form.add_error("username", "用户名或密码错误")
return render(request, "login.html", {'form': form})
return render(request, "login.html", {'form': form})

login.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>用户登录</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="{% static 'plugins/bootstrap-3.4.1/css/bootstrap.min.css' %}">
<link rel="stylesheet" href="{% static 'plugins/fontawesome-free-6.2.1-web/css/fontawesome.min.css' %}">
<link rel="stylesheet" href="{% static 'css/login.css' %}">
<style>
body {
margin: 0;
padding: 0;
}

html, body {
width: 100%;
height: 100%;
}

.size {
width: 100%;
height: 100%;
}

#vcode {
height: 35px;
width: 50%;
display: inline-block;
/*padding-left: 8px;*/
}

#code {
color: #ffffff;
/*字体颜色白色*/
background: linear-gradient(plum, powderblue);
height: 35px;
width: 150px;
float: right;
text-align: center;
font-size: 18pt;
/*margin: 5px auto;*/
/*font-family: "华康娃娃体W5";*/
padding: 5px 35px 10px 35px;
margin-left: 5%;
cursor: pointer;
}
</style>
</head>
<body>

<div class="container size">
<div class="login-wrapper" style="height: 600px;">
<form method="post" onsubmit="return check()" novalidate>
{% csrf_token %}
<div class="header">Login</div>
<div class="form-wrapper clearfix">
{{ form.username }}
<span>{{ form.username.errors }}</span>
{{ form.password }}
<span>{{ form.password.errors }}</span>
<input type="text" autocomplete="false" id="vcode" required="required" placeholder="验证码"
class="input-item"
/><span id="code"></span>
<input class="sub" type="submit" value="Login"></input>
</div>
<div class="msg">
Do not have account? <a href="/register">sign up</a>
</div>
</form>
</div>
</div>

<script type="text/javascript">

var code; //声明一个变量用于存储生成的验证码
changeImg();
document.getElementById("code").onclick = changeImg;


function changeImg() {
var arrays = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
'u', 'v', 'w', 'x', 'y', 'z',
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
'U', 'V', 'W', 'X', 'Y', 'Z'];
code = ''; //重新初始化验证码
//alert(arrays.length);
//随机从数组中获取四个元素组成验证码
for (var i = 0; i < 4; i++) {
//随机获取一个数组的下标
var r = parseInt(Math.random() * arrays.length);
code += arrays[r];
}
document.getElementById('code').innerHTML = code; //将验证码写入指定区域
}

//效验验证码(表单被提交时触发)
function check() {

//获取用户输入的验证码
let input_code = document.getElementById('vcode').value;
if (input_code.toLowerCase() === code.toLowerCase()) {
return true
} else {
alert("请输入正确的验证码!");
return false;
}
{#let username = $("#id_username").val();#}
{#let pwd = $("#id_password").val();#}
{#console.log(username, pwd);#}
{#if (!(username && pwd)) {#}
{# alert("输入信息不完整,请继续输入");#}
{# return false;#}

{#else if (username && pwd && input_code.toLowerCase() === code.toLowerCase()) {#}
{# //验证码正确(表单提交)#}
{# return true;#}

{#else {#}
{# alert("请输入正确的验证码!");#}
{# //验证码不正确,表单不允许提交#}
{# return false;#}

}

</script>
<script src="https://kit.fontawesome.com/2503dce09a.js" crossorigin="anonymous"></script>
<script src="{% static 'js/jquery-3.6.1.min.js' %}"></script>
<script src="{% static 'plugins/bootstrap-3.4.1/js/bootstrap.min.js' %}"></script>
</body>
</html>

7.中间件处理

1.定义中间件

==进入中间件请求时(process_request)若无返回值则继续向前,否则执行process_reponse直接返回。==

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from django.utils.deprecation import MiddlewareMixin


class M1(MiddlewareMixin):
"""中间件1"""

def process_request(self, request):
# 若无返回值则继续向前走,否则直接返回
print("M1.进来了")

def process_reponse(self, request, response):
print("M1.走了")
return response


class M2(MiddlewareMixin):
"""中间件2"""

def process_request(self, request):
print("M2.进来了")

def process_reponse(self, request, response):
print("M2.走了")
return response

2.应用中间件(setting.py)

1
2
3
4
5
6
7
8
9
10
11
12
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
# 谁在前面先执行谁
"staffsys.middleware.auth.M1",
"staffsys.middleware.auth.M2",
]

3.中间件方法

1
2
#如果方法中没有返回值(返回None),继续向后走
#如果有返回值HttpResponse、reder、redirect,则不再继续向后执行

8.中间件实现登录校验

实现对用户信息的保存。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import redirect


class LoginAuth(MiddlewareMixin):
"""中间件1"""

def process_request(self, request):
# 1.排除哪些不需要登录的页面
# request.path_info获取当前用户请求的url
if request.path_info == "/login/":
return
# 2.读取当前访问的用户的session信息,如果能读到,说明已登录鉴权,可以继续向后走
info_dict = request.session.get("info")
if info_dict:
return
# 3.没有登录过,返回到登录界面
return redirect("/login/")

def process_response(self, request, response):
print("LoginAuth.走了")
return response

9.用户注销

1
2
3
4
def logout(request):
"""注销"""
request.session.clear()
return redirect("/login/")

10.图片验证码

==python生成图片验证码的函数==

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
import random

from PIL import ImageFilter, ImageFont, Image, ImageDraw


def check_code(width=150, height=35, char_length=4,
font_file='Monaco.ttf', font_size=28):
code = []
img = Image.new(mode='RGB', size=(width, height), color=(255, 255, 255))
draw = ImageDraw.Draw(img, mode='RGB')

def rndChar():
"""
生成随机字母
:return:
"""
return chr(random.randint(65, 90))

def rndColor():
"""
生成随机颜色
:return:
"""
return (random.randint(0, 255), random.randint(10, 255), random.randint(64, 255))

# 写文字
font = ImageFont.truetype(font_file, font_size)
for i in range(char_length):
char = rndChar()
code.append(char)
h = random.randint(0, 4)
draw.text([i * width / char_length, h], char, font=font, fill=rndColor())

# 写干扰点
for i in range(40):
draw.point([random.randint(0, width), random.randint(0, height)], fill=rndColor())

# 写干扰圆圈
for i in range(40):
draw.point([random.randint(0, width), random.randint(0, height)], fill=rndColor())
x = random.randint(0, width)
y = random.randint(0, height)
draw.arc((x, y, x + 4, y + 4), 0, 90, fill=rndColor())

# 画干扰线
for i in range(5):
x1 = random.randint(0, width)
y1 = random.randint(0, height)
x2 = random.randint(0, width)
y2 = random.randint(0, height)

draw.line((x1, y1, x2, y2), fill=rndColor())

img = img.filter(ImageFilter.EDGE_ENHANCE_MORE)
return img, ''.join(code)

# if __name__ == '__main__':
# 1. 直接打开
# img,code = check_code()
# img.show()

# 2. 写入文件
# img, code = check_code()
# with open('../static/img/check_code.png', 'wb') as f:
# img.save(f, format='png')
# print(code)

# 3. 写入内存(Python3)
# from io import BytesIO
# stream = BytesIO()
# img.save(stream, 'png')
# stream.getvalue()

# 4. 写入内存(Python2)
# import StringIO
# stream = StringIO.StringIO()
# img.save(stream, 'png')
# stream.getvalue()

pass

==登录表单==

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class LoginForm(bootstrapmodelform.BootStrapForm):
"""登录表单"""
username = forms.CharField(
label="用户名",
max_length=32,
widget=forms.TextInput,
required=True,
)
password = forms.CharField(
label="密码",
max_length=64,
widget=forms.PasswordInput(render_value=True),
required=True,
)
code = forms.CharField(
label="验证码",
widget=forms.TextInput(),
required=True
)

def clean_password(self):
pwd = self.cleaned_data.get("password")
return md5(pwd)

==登录视图==

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
def login(request):
"""登录"""
if request.method == "GET":
form = LoginForm()
return render(request, "login.html", {'form': form})
form = LoginForm(data=request.POST)
if form.is_valid():
# 验证成功,获取输入信息
# {'username': 'alleyf', 'password': '123', 'code': 'csfd'}
# 验证码校验,取出并出栈验证码,防止后面校验多出数据库中没有的验证码
usr_input_code = form.cleaned_data.pop('code')
checkcode = request.session.get('checkcode', '')
if checkcode.lower() != usr_input_code.lower():
form.add_error('code', '验证码错误')
return render(request, 'login.html', {'form': form})
# 去数据库校验用户名和密码是否存在且正确
usrobj = Admin.objects.filter(**form.cleaned_data).first()
if usrobj:
# 用户名和密码正确
# 构建session信息
request.session["info"] = {"id": usrobj.id, "name": usrobj.username}
# 设置用户信息保存7天
request.session.set_expiry(60 * 60 * 24 * 7)
return redirect("/admin/list/")
form.add_error("username", "用户名或密码错误")
return render(request, "login.html", {'form': form})
return render(request, "login.html", {'form': form})

==图片验证码视图==

1
2
3
4
5
6
7
8
9
10
11
12
def checkcode(request):
"""图片验证码"""
# 调用函数生成图片验证码
img, code = check_code()
# 将验证码写入到自己的session中(以便于后续校验)
request.session['checkcode'] = code
# 给session设置有效时长为60s
request.session.set_expiry(60)
# 将图片写入内存
stream = BytesIO()
img.save(stream, 'png')
return HttpResponse(stream.getvalue())

==前端login.html==

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
{% block mytitle %}
<title>用户登录</title>
{% endblock %}
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="{% static 'plugins/bootstrap-3.4.1/css/bootstrap.min.css' %}">
<link rel="stylesheet" href="{% static 'plugins/fontawesome-free-6.2.1-web/css/fontawesome.min.css' %}">
<link rel="stylesheet" href="{% static 'css/login.css' %}">
<style>
body {
margin: 0;
padding: 0;
}

html, body {
width: 100%;
height: 100%;
}

.size {
width: 100%;
height: 100%;
}

#vcode {
height: 35px;
width: 50%;
display: inline-block;
/*padding-left: 8px;*/
}

#code {
color: #ffffff;
/*字体颜色白色*/
background: linear-gradient(plum, powderblue);
height: 35px;
width: 150px;
float: right;
text-align: center;
font-size: 18pt;
/*margin: 5px auto;*/
/*font-family: "华康娃娃体W5";*/
padding: 5px 35px 10px 35px;
margin-left: 5%;
cursor: pointer;
}
</style>
{% block mystyle %}
{% endblock %}
</head>
<body>
{% block myinfo %}
<div class="container size">
<div class="login-wrapper" style="height: 620px;">
<form method="post" onsubmit="return check()" novalidate>
{% csrf_token %}
<div class="header">Login</div>
<div class="form-wrapper clearfix">
{{ form.username }}
<span style="color: red;">{{ form.username.errors }}</span>
{{ form.password }}
<span style="color: red">{{ form.password.errors }}</span>
{# <input type="text" autocomplete="false" id="vcode" required="required" placeholder="验证码"#}
{# class="input-item col-xs-7"#}
{# /><span id="code" class="col-xs-5"></span>#}
<div class="row clearfix">
<div class="col-xs-7">
{{ form.code }}
<span style="color: red">{{ form.code.errors }}</span>
</div>
<div class="col-xs-5">
<a href="/checkcode/">
<img src="/checkcode/" alt="图片加载失败">
</a>
</div>
</div>
<input class="sub" type="submit" value="Login">
</div>
</form>
<div class="msg">
Do not have account? <a href="/register">sign up</a>
</div>
</div>
</div>
{% endblock %}


<script type="text/javascript">

var code; //声明一个变量用于存储生成的验证码
changeImg();
document.getElementById("code").onclick = changeImg;


function changeImg() {
var arrays = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
'u', 'v', 'w', 'x', 'y', 'z',
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
'U', 'V', 'W', 'X', 'Y', 'Z'];
code = ''; //重新初始化验证码
//alert(arrays.length);
//随机从数组中获取四个元素组成验证码
for (var i = 0; i < 4; i++) {
//随机获取一个数组的下标
var r = parseInt(Math.random() * arrays.length);
code += arrays[r];
}
document.getElementById('code').innerHTML = code; //将验证码写入指定区域
}

//效验验证码(表单被提交时触发)
function check() {

//获取用户输入的验证码
let input_code = document.getElementById('vcode').value;
if (input_code.toLowerCase() === code.toLowerCase()) {
return true
} else {
alert("请输入正确的验证码!");
return false;
}
{#let username = $("#id_username").val();#}
{#let pwd = $("#id_password").val();#}
{#console.log(username, pwd);#}
{#if (!(username && pwd)) {#}
{# alert("输入信息不完整,请继续输入");#}
{# return false;#}

{#else if (username && pwd && input_code.toLowerCase() === code.toLowerCase()) {#}
{# //验证码正确(表单提交)#}
{# return true;#}

{#else {#}
{# alert("请输入正确的验证码!");#}
{# //验证码不正确,表单不允许提交#}
{# return false;#}

}

</script>
<script src="https://kit.fontawesome.com/2503dce09a.js" crossorigin="anonymous"></script>
<script src="{% static 'js/jquery-3.6.1.min.js' %}"></script>
<script src="{% static 'plugins/bootstrap-3.4.1/js/bootstrap.min.js' %}"></script>
</body>
</html>

11.Ajax请求

前后端数据交互出了表单方式(页面会刷新)外,还有ajax异步请求(页面不刷新)。

  • 依赖Jquery

  • 编写Ajax代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    <script type="text/javascript">
    $(function () {
    $.ajax({
    url: "https://v1.hitokoto.cn/",
    type: 'get',
    data: {
    c: 'i'
    },
    success: function (res) {
    let poem = res["hitokoto"];
    let source = res["from"];
    let word = poem + "---" + source;
    $("#w1").text(word)
    console.log(res["from"])
    }
    })
    })
    </script>

1.get请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<script type="text/javascript">
$(function () {
$.ajax({
url: "https://v1.hitokoto.cn/",
type: 'get',
data: {
c: 'i'
},
success: function (res) {
let poem = res["hitokoto"];
let source = res["from"];
let word = poem + "---" + source;
$("#w1").text(word)
console.log(res["from"])
}
})
})
</script>

2.post请求

==视图函数必须加入这个去除csrf校验,因为ajax表单请求时未包含csrf信息,from django.views.decorators.csrf import csrf_exempt @csrf_exempt==

前端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<script type="text/javascript">
$(function () {
$.ajax({
url: "/task/ajax",
type: 'post',
data: {
c: 'i'
},
success: function (res) {
let poem = res["hitokoto"];
let source = res["from"];
let word = poem + "---" + source;
$("#w1").text(word)
console.log(res["from"])
}
})
})
</script>

后端

1
2
3
4
5
6
7
8
from django.shortcuts import render ,HttpResponse
from django.views.decorators.csrf import csrf_exempt

@csrf_exempt
def task_ajax(request):
print(request.GET)
print(request.POST)
return HttpResponse("成功了")

3.绑定事件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
{% block myscript %}
<script type="text/javascript">
//框架加载完毕执行
$(function () {
bindw1span();
})

function bindw1span() {
$.ajax({
url: "https://v1.hitokoto.cn/",
type: 'get',
data: {
c: 'i'
},
success: function (res) {
let poem = res["hitokoto"];
let source = res["from"];
let word = poem + "---" + source;
$("#w1").text(word)
console.log(res["from"])
}
})
}
</script>
{% endblock %}

4.ajax请求的返回值

==django项目运行的目录为工程下的根目录(manage.py或app文件夹同级目录)==

一般都会返回json格式。

后端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@csrf_exempt
def task_ocr(request):
"""ajax请求"""
imgpath = request.GET.get("imgpath")
results = []
res = ocr_geberaltext(path=imgpath)
for item in res["TextDetections"]:
temp_dict = {
"DetectedText": item["DetectedText"],
"Confidence": item["Confidence"]
}
results.append(temp_dict)
data_dict = {
"status": True,
'results': results
}
# 1.用json.dumps()函数
# json_str = json.dumps(data_dict)
# return json_str
# 2.直接返回JsonResponse
return JsonResponse(data_dict)

前端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
{% block myscript %}
<script type="text/javascript">
$(function () {
bindw1span();
ocr();
})

function bindw1span() {
$.ajax({
url: "https://v1.hitokoto.cn/",
type: 'get',
data: {
c: 'i'
},
success: function (res) {
let poem = res["hitokoto"];
let source = res["from"];
let word = poem + "---" + source;
$("#w1").text(word)
console.log(res["from"])
}
})
}

function ocr() {
$.ajax({
url: "/task/ocr/",
type: 'get',
data: {
imgpath: "./staffsys/static/img/1.png"
},
success: function (res) {
console.log(res)
}
})
}
</script>
{% endblock %}

5.实例:TODO_List

1.数据表结构
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Admin(models.Model):
"""管理员"""
username = models.CharField(verbose_name="用户名", max_length=32)
password = models.CharField(verbose_name="密码", max_length=64)

def __str__(self):
return self.username

class Task(models.Model):
"""任务"""
level_choices = (
(1, '紧急'),
(2, '重要'),
(3, '临时')
)
title = models.CharField(verbose_name='标题', max_length=64)
details = models.TextField(verbose_name='内容')
level = models.SmallIntegerField(verbose_name='级别', choices=level_choices, default=3)
user = models.ForeignKey(verbose_name='负责人', to=Admin, on_delete=models.CASCADE)

2.表单模型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
from django import forms

"""----------1简约型(class=input form-control)--------------2酷炫型(class=input-item)---------"""


# 1.适合增改查的风格
class BootStrap1:
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# 2.批量设置样式:循环找到所有的字段,给其添加相同样式
for name, field in self.fields.items():
# 有责修改样式
if field.widget.attrs:
field.widget.attrs["class"] = "input form-control"
field.widget.attrs["placeholder"] = field.label

# 无责添加样式
else:
field.widget.attrs = {"class": "input form-control", "placeholder": field.label}


# 2.适合登陆注册的风格
class BootStrap2:
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# 2.批量设置样式:循环找到所有的字段,给其添加相同样式
for name, field in self.fields.items():
# 有责修改样式
if field.widget.attrs:
field.widget.attrs["class"] = "input-item"
field.widget.attrs["placeholder"] = field.label

# 无责添加样式
else:
field.widget.attrs = {"class": "input-item", "placeholder": field.label}


class BootStrapModelForm1(BootStrap1, forms.ModelForm):
pass


class BootStrapModelForm2(BootStrap2, forms.ModelForm):
pass


class BootStrapForm(BootStrap2, forms.Form):
pass


class TaskModelForm(bootstrapmodelform.BootStrapModelForm1):
class Meta:
model = models.Task
fields = "__all__"
# fields = ["title", "details", "level", "user"]
widgets = {
"details": forms.TextInput()
}
3.视图函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
import json
from random import randint

from django.http import JsonResponse
from django.shortcuts import render, redirect
from django.views.decorators.csrf import csrf_exempt

from staffsys import models
from staffsys.utils import pagination
from staffsys.utils.form import TaskModelForm
from staffsys.utils.ocr import ocr_geberaltext


def todo_list(request):
"""任务列表"""
# 图片随机数种子
rps = []
for i in range(3):
rps.append(randint(0, 100))
if request.method == "GET":
form = TaskModelForm()
# 1.搜索参数初始化
search_dict = {}
# 获取号码搜索参数
search_data = request.GET.get(key="t", default='')
if search_data:
search_dict['details__contains'] = search_data
# 2.页码参数初始化
pagesize = 10
pageplus = 2
# 3.筛选符合条件的数据
queryset = models.Task.objects.filter(**search_dict).order_by('id')
# 4.实例化页面对象
page_obj = pagination.Pagination(request, query_set=queryset, page_size=pagesize, page_plus=pageplus)
# 5.获取页面数据
page_queryset = page_obj.page_queryset
page_str = page_obj.htmlstr()
print(page_queryset)
context = {
'ran_pic_seed': rps,
'form': form,
# 页面数据信息
'page_queryset': page_queryset,
# 搜索参数
'search_data': search_data,
# 分页html字符串组件
'page_str': page_str
}
return render(request, "ToDo_List.html", context)


@csrf_exempt
def task_ocr(request):
"""ajax请求ocr识别"""
imgpath = request.POST.get("imgpath")
print(request.POST)
results = []
# res = ocr_geberaltext(path=imgpath)
# for item in res["TextDetections"]:
# temp_dict = {
# "DetectedText": item["DetectedText"],
# "Confidence": item["Confidence"]
# }
# results.append(temp_dict)
data_dict = {
"status": True,
'results': results
}
# 1.用json.dumps()函数
# json_str = json.dumps(data_dict)
# return json_str
# 2.直接返回JsonResponse
return JsonResponse(data_dict)


@csrf_exempt
def todo_add(request):
"""添加任务接口"""
form = TaskModelForm(data=request.POST)
# 信息校验
if form.is_valid():
form.save()
resinfo = {
'status': True
}
return JsonResponse(resinfo)
resinfo = {
'status': False,
'err': form.errors
}
return JsonResponse(resinfo)
4.前端页面

==layout.html==

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
{% block mytitle %}
<title>标题</title>
{% endblock %}
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet"
href="{% static 'plugins/bootstrap-datetimepicker-master/css/bootstrap-datetimepicker.min.css' %}">
<link rel="stylesheet" href="{% static 'plugins/bootstrap-3.4.1/css/bootstrap.min.css' %}">
<link rel="stylesheet" href="{% static 'plugins/fontawesome-free-6.2.1-web/css/fontawesome.min.css' %}">
<style>
* {
padding: 0;
margin: 0;
font-family: 微软雅黑, serif;
letter-spacing: .05em;
}

th {
text-align: center;
}

.navbar {
border-radius: 0;
}

.navbar ul a {
line-height: 30px;
}

.lh30 {
line-height: 30px;
}
</style>
{% block mystyle %}
{% endblock %}
</head>
<body>
<nav class="navbar navbar-default">
<div class="container">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse"
data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand lh30" href="#">联通用户管理系统</a>
</div>

<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li class=""><a href="/depart/list/">部门管理<span class="sr-only">(current)</span></a></li>
<li class=""><a href="/user/list/">用户管理</a></li>
<li class=""><a href="/phone/list/">靓号管理</a></li>
<li class=""><a href="/task/list/">今日清单</a></li>
<li class=""><a href="/admin/list/">管理员账户</a></li>
</ul>
<ul class="nav navbar-nav navbar-right">
<li><a href="#" style="padding: 5px;"><img alt="50x50" src="{% static 'img/03.webp' %}"
width="50px" height="50px"
class="img-circle"/></a></li>
<li class="dropdown">
<a href=" #" class="dropdown-toggle" data-toggle="dropdown" role="button"
aria-haspopup="true"
aria-expanded="false">{{ request.session.info.name }} <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="#">个人资料</a></li>
<li><a href="#">我的信息</a></li>
<li role="separator" class="divider"></li>
<li><a href="/logout">注销</a></li>
</ul>
</li>
</ul>
</div>
</div>
</nav>
<div>
{% block info %}{% endblock %}
</div>
<script src="https://kit.fontawesome.com/2503dce09a.js" crossorigin="anonymous"></script>
<script src="{% static 'js/jquery-3.6.1.min.js' %}"></script>
<script src="{% static 'plugins/bootstrap-3.4.1/js/bootstrap.min.js' %}"></script>
<script src="{% static 'plugins/bootstrap-datetimepicker-master/js/bootstrap-datetimepicker.min.js' %}"></script>
{% block myscript %}
{% endblock %}
</body>

==ToDo_List.html==

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
{% extends 'layout.html' %}
{% block mytitle %}
<title>今日清单</title>
{% endblock %}
{% block mystyle %}
<style>
.input {
display: inline-block;
margin: 10px auto;
min-height: 50px;
width: 300px;
padding: 0 1rem;
color: #1e2732;
font-size: 15px;
border: 1px solid #5e4dcd;
border-radius: 6px;
background-color: transparent;
}

.button--submit {
display: block;
margin: 10px auto;
min-height: 50px;
padding: .5em 1em;
border: none;
border-radius: 6px;
background-color: #5e4dcd;
color: #fff;
font-size: 15px;
cursor: pointer;
transition: background-color .3s ease-in-out;
}

.button--submit:hover {
background-color: #5e5dcd;
}

.input:focus, .input:focus-visible {
border-color: #3898EC;
outline: none;
}
</style>
{% endblock %}
{% block info %}
<div class="container">
<div style="margin-bottom: 10px" class="clearfix">
<a href="/admin/add/" class="btn btn-primary"><i class="fa fa-plus"></i>新建清单</a>
<span id="w1" style="color: #5b65f1;font-size: 24px"></span>
<div style="float: right;width: 300px">
<form method="get">
<div class="input-group">
<input type="text" name="t" placeholder="Search for task" class="form-control"
value={{ search_data }}>
<span class="input-group-btn">
<button class="btn btn-default"><i class="fa fa-search"></i> </button>
</span>
</div>
</form>
</div>
</div>
<div class="panel panel-info">
<div class="panel-heading"><i class="fa fa-list"></i>任务列表</div>
<div class="panel-body">
<div class="row">
{% block myform %}
<form class="input-group col-md-12" id="addtaskinfoform" novalidate>
{% for item in form %}
<div class="form-group col-md-6">
<label>{{ item.label }}</label>
<span class="err_msg" style="color: #c12c1f"></span>
{{ item }}
</div>
{% endfor %}
<div class="col-md-12">
<button type="button" class="button--submit" id="addtask">提交</button>
</div>
</form>
{% endblock %}
</div>
<div class="row">
{% for item in page_queryset %}
<div class="col-md-4">
<div class="thumbnail">
<img alt="300x200" src="https://picsum.photos/id/{{ ran_pic_seed.0 }}/600/300"/>
<div class="caption text-center">
<h3 style="color: #757cbb">
{{ item.title }}
</h3>
<p>
{{ item.details }}
</p>
<p>
<a class="btn btn-info" href="#">开始</a> <a class="btn btn-success"
href="#">结束</a>
</p>
</div>
</div>
</div>
{% endfor %}
</div>
</div>
</div>
<div class="text-center">
<ul class="pagination pagination-xs">
{{ page_str }}
</ul>
</div>
</div>
{% endblock %}

{% block myscript %}
<script type="text/javascript">
$(function () {
bindslogin();
{#ocr();#}
bindaddtask()
})

function bindslogin() {
$.ajax({
url: "https://v1.hitokoto.cn/",
type: 'get',
data: {
c: 'i'
},
success: function (res) {
let poem = res["hitokoto"];
let source = res["from"];
let word = poem + "---" + source;
$("#w1").text(word)
console.log(res["from"])
}
})
}

function ocr() {
$.ajax({
url: "/task/ocr/",
type: 'post',
data: {
imgpath: "./staffsys/static/img/1.png"
},
dataType: "json",
success: function (res) {
console.log(res)
}
})
}

function bindaddtask() {
$("#addtask").click(function () {
$(".err_msg").empty();
$.ajax({
url: "/task/add/",
type: 'post',
data: $("#addtaskinfoform").serialize(),
dataType: "json",
success: function (res) {
if (res.status) {
{#弹出添加成功响应#}
alert("添加成功");
location.reload();
} else {
$.each(res.err, function (name, data) {
{#将错误信息添加到前端#}
$("#id_" + name).prev().text(data[0]);
})
}
}
})
})
}
</script>
{% endblock %}

12.文献管理

1.表结构

id 文献名称 作者 来源 命中率 得分
1 2016IJC-导管组织接触对于模型的影响PentarRay FAM 陈明龙 本地数据库 85% 88
2 FOCUS超声刀开放性甲状腺切除术的临床疗效评价 薛家鹏 网页爬虫 92% 94

2.路由

1
2
3
4
5
6
7
8
# 文档列表
path("doc/list/", doc.doc_list),
# 添加文档
path("doc/add/", doc.doc_add),
# 删除文献
path("doc/del/", doc.doc_del),
# 编辑文献
path("doc/edit/", doc.doc_edit)

3.视图层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
from django.http import JsonResponse
from django.shortcuts import render
from django.views.decorators.csrf import csrf_exempt
from datetime import datetime

from staffsys import models
from staffsys.utils import pagination
from staffsys.utils.form import DocModelForm


def doc_list(request):
form = DocModelForm()
# 1.搜索参数初始化
search_dict = {}
# 获取号码搜索参数
search_data = request.GET.get(key="n", default='')
if search_data:
search_dict['name__contains'] = search_data
# 2.页码参数初始化
pagesize = 10
pageplus = 2
# 3.筛选符合条件的数据
queryset = models.Documents.objects.filter(**search_dict).order_by('-allscore')
# 4.实例化页面对象
page_obj = pagination.Pagination(request, query_set=queryset, page_size=pagesize, page_plus=pageplus)
# 5.获取页面数据
page_queryset = page_obj.page_queryset
page_str = page_obj.htmlstr()
context = {
'form': form,
# 页面数据信息
'page_queryset': page_queryset,
# 搜索参数
'search_data': search_data,
# 分页html字符串组件
'page_str': page_str
}
print(datetime.now().strftime('%Y%m%d%H%M%S'))
return render(request, "doc_list.html", context)


@csrf_exempt
def doc_add(request):
"""添加文档"""
form = DocModelForm(data=request.POST)
if form.is_valid():
# 后台添加无需前端输入的表信息(字段)
form.instance.status = 1
# 将当前登录的用户作为该条信息的作者
form.instance.user_id = request.session['info'].get("id")
form.save()
context = {
'status': True,
}
return JsonResponse(context)
context = {
'status': False,
'err': form.errors
}
return JsonResponse(context)


def doc_del(request):
uid = request.GET.get('uid')
exist = models.Documents.objects.filter(id=uid).exists()
if exist:
models.Documents.objects.filter(id=uid).first().delete()
res = {
'status': True,
}
return JsonResponse(res)
res = {
'status': False,
'err': 'ID为' + uid + '的文件不存在,删除失败'
}
return JsonResponse(res)


@csrf_exempt
def doc_edit(request):
"""编辑文献"""
# 根据id获取文献信息
uid = request.GET.get('uid')
# 编辑文献
rowobj = models.Documents.objects.filter(id=uid).first()
if not rowobj:
res = {
'status': False,
'tips': 'ID为' + uid + '的文件不存在,请刷新重试'
}
return JsonResponse(res)
form = DocModelForm(data=request.POST, instance=rowobj)
if form.is_valid():
form.save()
res = {
'status': True
}
return JsonResponse(res)
context = {
'status': False,
'err': form.errors
}
return JsonResponse(context)


def doc_details(request):
# 根据id获取文献信息
uid = request.GET.get('uid')
# 方法1获取对象
# rowobj = models.Documents.objects.filter(id=uid).first()
# if not rowobj:
# res = {
# 'status': False,
# 'err': 'ID为' + uid + '的文件不存在,打开失败'
# }
# return JsonResponse(res)
# res = {
# 'status': True,
# 'data': {
# 'name': rowobj.name,
# 'author': rowobj.author,
# 'clkscore': rowobj.clkscore,
# 'fedbakscore': rowobj.fedbakscore,
# 'status': rowobj.status,
# 'user': rowobj.user.username
# }
# }
# return JsonResponse(res)
# 方法2获取字典
rowdic = models.Documents.objects.filter(id=uid).values('name', 'author', 'source').first()
if not rowdic:
res = {
'status': False,
'err': 'ID为' + uid + '的文件不存在,打开失败'
}
return JsonResponse(res)
res = {
'status': True,
'data': rowdic
}
return JsonResponse(res)

4.模板层

==doc_list.html==

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
{% extends 'layout.html' %}
{% block mytitle %}
<title>医学文献-易管理</title>
{% endblock %}
{% block mystyle %}
<style>
.input {
display: inline-block;
margin: 10px auto;
min-height: 50px;
width: 300px;
padding: 0 1rem;
color: #1e2732;
font-size: 15px;
border: 1px solid #5e4dcd;
border-radius: 6px;
background-color: transparent;
}

.button--submit {
display: block;
margin: 10px auto;
min-height: 50px;
padding: .5em 1em;
border: none;
border-radius: 6px;
background-color: #5e4dcd;
color: #fff;
font-size: 15px;
cursor: pointer;
transition: background-color .3s ease-in-out;
}

.button--submit:hover {
background-color: #5e5dcd;
}

.input:focus, .input:focus-visible {
border-color: #3898EC;
outline: none;
}
</style>
{% endblock %}

{% block info %}
<!-- 添加/编辑文献【对话框】 -->
<div class="modal fade" id="addModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
aria-hidden="true">&times;</span></button>
<h4 class="modal-title" id="myModalLabel">添加</h4>
</div>
<div class="modal-body">
<form class="input-group col-md-12" id="formadd" novalidate>
{% for item in form %}
<div class="form-group col-md-12">
<label>{{ item.label }}</label>
<span class="err_msg" style="color: #c12c1f"></span>
{{ item }}
</div>
{% endfor %}
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
<button type="button" class="btn btn-info" id="submitbtn">提交</button>
</div>
</div>
</div>
</div>
{# 删除对话框#}
<div class="modal fade" id="delModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
<div class="modal-dialog" role="document">
<div class="alert alert-danger alert-dismissible fade in" role="alert">
<h4><strong>是否确定删除?</strong></h4>
<p style="margin: 10px 0;">一旦删除,所有关联的相关数据都会被删除!</p>
<p style="text-align: right">
<button type="button" class="btn btn-danger btn_del_yes">确 定</button>
<button type="button" class="btn btn-default" data-dismiss="modal">取 消</button>
</p>
</div>
</div>
</div>
<div class="container">
<div style="margin-bottom: 10px" class="clearfix">
<button type="button" id="adddoc" class="btn btn-primary"><i class="fa fa-plus"></i>
添加文献
</button>
<div style="float: right;width: 300px">
<form method="get">
<div class="input-group">
<input type="text" name="n" placeholder="Search for docname" class="form-control"
value={{ search_data }}>
<span class="input-group-btn">
<button class="btn btn-default"><i class="fa fa-search"></i> </button>
</span>
</div>
</form>
</div>
</div>
<div class="panel panel-info">
<div class="panel-heading"><i class="fa fa-list"></i>文献列表</div>
<table class="table table-hover table-condensed ">
<thead>
<tr>
<th>ID</th>
<th>文献名</th>
<th>作者</th>
<th>点击量得分</th>
<th>用户反馈得分</th>
<th>归档</th>
<th>来源</th>
<th>管理员</th>
<th>操作</th>
</tr>
</thead>
<tbody class="text-center">
{% for pninfo in page_queryset %}
<tr uid="{{ pninfo.id }}">
<th scope="row">{{ pninfo.id }}</th>
<td>{{ pninfo.name }}</td>
<td>{{ pninfo.author }}</td>
<td>{{ pninfo.clkscore }}</td>
<td>{{ pninfo.fedbakscore }}</td>
<td>{{ pninfo.get_status_display }}</td>
<td>{{ pninfo.get_source_display }}</td>
<td>{{ pninfo.user.username }}</td>
<td>
<input uid="{{ pninfo.id }}" type="button" class="btn btn-default btn-xs btn_edit"
value="编辑">
<input uid="{{ pninfo.id }}" type="button" class="btn btn-primary btn-xs btn_view"
value="查看">
<input uid="{{ pninfo.id }}" type="button" class="btn btn-danger btn-xs btn_del" value="删除">
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<div class="text-center">
<ul class="pagination pagination-xs">
{{ page_str }}
</ul>
</div>
</div>

{% endblock %}

{% block myscript %}
<script type="text/javascript">
var DELETE_ID;
var EDIT_ID;
$(function () {
bindbtnadd();
bindbtnsave();
bindbtndel();
bindbtnedit();
})

function bindbtnadd() {
$("#adddoc").click(function () {
$(".err_msg").empty();
{#将当前编辑ID置空#}
EDIT_ID = undefined;
{#清空已有的数据#}
$("#formadd")[0].reset();
$('#addModal').modal('show');
})
}

function bindbtnsave() {
$("#submitbtn").click(function () {
if (EDIT_ID) {
{#发送编辑请求#}
doedit();
} else {
{#发送天加请求#}
doadd();
}
})

}

function doadd() {
console.log("发送添加请求")
$(".err_msg").empty();
{#添加文献#}
$.ajax({
url: "/doc/add/",
type: "post",
data: $("#formadd").serialize(),
dataType: "json",
success: function (res) {
if (res.status) {
{#$("#formadd")为jquery对象,$("#formadd")[0]为dom对象#}
{#$("#formadd")[0].reset();#}
{#$('#myModal').modal('hide');#}
location.reload();
} else {
$.each(res.err, function (name, errmsglist) {
$("#id_" + name).prev().text(errmsglist[0])
})
}
}
})
}

function doedit() {
console.log("发送编辑请求")
$(".err_msg").empty();
{#编辑文献#}
$.ajax({
url: "/doc/edit/" + "?uid=" + EDIT_ID,
type: "post",
data: $("#formadd").serialize(),
dataType: "json",
success: function (res) {
if (res.status) {
{#$("#formadd")为jquery对象,$("#formadd")[0]为dom对象#}
{#$("#formadd")[0].reset();#}
{#$('#myModal').modal('hide');#}
location.reload();
} else {
if (res.tips) {
{#文献不存在错误#}
alert(res.tips)
$('#myModal').modal('hide');
} else {
{#文献信息编辑填写错误#}
$.each(res.err, function (name, errmsglist) {
$("#id_" + name).prev().text(errmsglist[0])
})
}
}
}
})
}

function bindbtndel() {
$(".btn_del").click(function () {
{#显示删除对话框#}
$('#delModal').modal('show');
{#获取当前行id并保存到全局变量中#}
DELETE_ID = $(this).attr('uid');
})
$(".btn_del_yes").click(function () {
$.ajax({
url: "/doc/del/",
type: 'get',
data: {
uid: DELETE_ID
},
dataType: 'json',
success: function (res) {
if (res.status) {
$('#delModal').modal('hide');
$("tr[uid=" + DELETE_ID + "]").remove();
{#location.reload();#}
} else {
alert(res.err)
$('#delModal').modal('hide');
console.log(res)
}

}
})
})
}

function bindbtnedit() {
$(".btn_edit").click(function () {
$(".err_msg").empty();
{#清空原有值#}
$("#formadd")[0].reset();
{#获取当前行id#}
let uid = $(this).attr('uid')
EDIT_ID = uid
{#发送Ajax请求去后端获取当前行的数据#}
$.ajax({
url: '/doc/edit/details',
type: 'get',
data: {
uid: uid
},
dataType: 'json',
success: function (res) {
if (res.status) {
console.log(res)
{#获取到的后端信息填充到表单中#}
$.each(res.data, function (name, value) {
$("#id_" + name).val(value)
})
{#修改对话框标题#}
$('#myModalLabel').text('编辑');
{#显示对话框#}
$('#addModal').modal('show');
} else {
alert(res.err)
}
}
})
})
}
</script>
{% endblock %}

想要去数据库获取数据时:对象/字典/queryset(列表包含对象)/queryset(列表包含字典)/queryset(列表包含元组)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 方法1获取对象
# rowobj = models.Documents.objects.filter(id=uid).first()
# if not rowobj:
# res = {
# 'status': False,
# 'err': 'ID为' + uid + '的文件不存在,打开失败'
# }
# return JsonResponse(res)
# res = {
# 'status': True,
# 'data': {
# 'name': rowobj.name,
# 'author': rowobj.author,
# 'clkscore': rowobj.clkscore,
# 'fedbakscore': rowobj.fedbakscore,
# 'status': rowobj.status,
# 'user': rowobj.user.username
# }
# }
# return JsonResponse(res)
1
2
3
4
5
6
7
8
9
10
11
12
13
# 方法2获取字典
rowdic = models.Documents.objects.filter(id=uid).values('name', 'author', 'source').first()
if not rowdic:
res = {
'status': False,
'err': 'ID为' + uid + '的文件不存在,打开失败'
}
return JsonResponse(res)
res = {
'status': True,
'data': rowdic
}
return JsonResponse(res)
1
2
# 方法3获取quertset = [obj1,obj2,obj3]
rowobj = models.Documents.objects.all()
1
2
# 方法3获取quertset = [dict1,dict2,dict3]
>rowobj = models.Documents.objects.all().values("id","name")
1
2
# 方法4获取quertset = [tuple1,tuple2,tuple3]
>rowobj = models.Documents.objects.all().values_list("id","name")

12.数据可视化

  • highchar,国外
  • echars,国内

1.视图层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
from django.http import JsonResponse
from django.shortcuts import render, redirect


def chart_list(request):
"""数据可视化页面"""
return render(request, "chart_list.html")


def chart_bar(request):
"""柱状图数据接口"""
# 去数据库中获取数据
# global series_list
legend = ['文献数量', '浏览量']
series_one = {
"name": '文献数量',
'type': 'bar',
'data': [1005, 2300, 1856, 2479, 3420, 5870]
}
series_two = {
'name': '浏览量',
'type': 'bar',
'data': [1200, 1625, 860, 1520, 2376, 1464]
}
series_list = [series_one, series_two]
x_axis = ['医学', '工学', '理学', '农学', '法学', '人文社科']
res = {
'status': True,
'data': {
'legend': legend,
'series_list': series_list,
'x_axis': x_axis
}
}
return JsonResponse(res)


def chart_pie(request):
"""饼状图数据接口"""
data_list = [
{"value": 1048, "name": '研发部'},
{"value": 735, "name": '后勤部'},
{"value": 580, "name": '运营部'},
{"value": 484, "name": '销售部'},
{"value": 300, "name": '售后部'}
]
res = {
'status': True,
'data': data_list
}
return JsonResponse(res)


def chart_line(request):
"""折线图数据接口"""
legend = ['alleyf', 'chuiyugin']
series_list = [
{
"name": legend[0],
"type": 'line',
"stack": 'Total',
"data": [3, 5, 4, 8, 6, 10, 5],
"smooth": True
},
{
"name": legend[1],
"type": 'line',
"stack": 'Total',
"data": [2, 5, 9, 3, 8, 12, 6],
"smooth": True
}
]
res = {
'status': True,
'data': {
'legend': legend,
'series_list': series_list
}
}
return JsonResponse(res)

2.模板层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
{% extends 'layout.html' %}
{% load static %}
{% block mytitle %}
<title>数据分析-可视化</title>
{% endblock %}

{% block info %}
<div class="container">
<div class="panel panel-primary">
<div class="panel-heading">折线图</div>
<div class="panel-body">
<div id="m1" style="width: 100%;height: 400px"></div>
<div id="m4" style="width: 100%;height: 400px"></div>
</div>
</div>
<div class="row">
<div class="col-sm-6">
<div class="panel panel-info">
<div class="panel-heading">柱状图</div>
<div class="panel-body">
<div id="m2" style="width: 100%;height: 400px"></div>
</div>
</div>
</div>
<div class="col-sm-6">
<div class="panel panel-success">
<div class="panel-heading">饼图</div>
<div class="panel-body">
<div id="m3" style="width: 100%;height: 400px"></div>
</div>
</div>
</div>
</div>
</div>

{% endblock %}

{% block myscript %}
<script src="{% static 'js/echarts.min.js' %}"></script>
<script type="text/javascript">
$(function () {
{#echarts图#}
initline()
initbar();
initpie();
{#highcharts图#}
inithbar();
})

function initbar() {
// 基于准备好的dom,初始化echarts实例
var myChart = echarts.init($('#m2')[0], 'dark');

// 指定图表的配置项和数据
var option = {
title: {
text: '文献种类概览',
{#副标题#}
subtext: '详情',
sublink: 'https://fcsy.fit',
{#标题居中#}
left: 'center'
},
tooltip: {},
legend: {
data: [], //后台数据更新
{#图例放在底部#}
bottom: 0
},
xAxis: {
data: []
},
yAxis: {},
series: []
};
$.ajax({
url: '/chart/bar/',
type: 'get',
dataType: 'json',
success: function (res) {
{#获取后台返回的数据#}
if (res.status) {
option.legend.data = res.data.legend;
option.xAxis.data = res.data.x_axis;
option.series = res.data.series_list;
myChart.setOption(option);
}
}
})
// 使用刚指定的配置项和数据显示图表。
}

function initpie() {
let myChart = echarts.init($('#m3')[0], 'dark');
let option;

option = {
title: {
text: '部门预算占比',
subtext: '陕西分部',
left: 'center'
},
tooltip: {
trigger: 'item'
},
legend: {
orient: 'vertical',
left: 'right',
},
series: [
{
name: '预算',
type: 'pie',
radius: '50%',
data: [],
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}
]
};
$.ajax({
url: '/chart/pie/',
type: 'get',
dataType: 'json',
success: function (res) {
if (res.status) {
option.series[0].data = res.data;
option && myChart.setOption(option);
}
}
})
}

function initline() {
var chartDom = $('#m1')[0];
var myChart = echarts.init(chartDom, 'dark');
var option;

option = {
title: {
text: '任务',
left: 'center'
},
tooltip: {
trigger: 'axis'
},
legend: {
data: [], //后台获取用户名
itemGap: 20,
bottom: 0
},
toolbox: {
feature: {
saveAsImage: {}
}
},
xAxis: {
type: 'category',
boundaryGap: false,
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
},
yAxis: {
type: 'value'
},
series: [
{
name: 'alleyf',
type: 'line',
stack: 'Total',
data: [120, 132, 101, 134, 90, 230, 210],
smooth: true
},
{
name: 'chuiyugin',
type: 'line',
stack: 'Total',
data: [220, 182, 191, 234, 290, 330, 310],
smooth: true
}
]
};
$.ajax({
url: '/chart/line/',
type: 'get',
dataType: 'json',
success: function (res) {
if (res.status) {
option.legend.data = res.data.legend;
option.series = res.data.series_list;
option && myChart.setOption(option);

}
}
})
}

function inithbar() {
// 图表配置
const options = {
chart: {
type: 'bar' //指定图表的类型,默认是折线图(line)
},
title: {
text: 'highchars' // 标题
},
xAxis: {
categories: ['苹果', '香蕉', '橙子'] // x 轴分类
},
yAxis: {
title: {
text: '吃水果个数' // y 轴标题
}
},
series: [{ // 数据列
name: '小明', // 数据列名
data: [1, 0, 4] // 数据
}, {
name: '小红',
data: [5, 7, 3]
}]
};
// 图表初始化函数
const chart = Highcharts.chart('m4', options);
}
</script>
<script src="http://cdn.highcharts.com.cn/highcharts/highcharts.js"></script>
{% endblock %}

13.文件上传

1.基础上传

1.视图层

1
2
3
4
5
6
7
8
9
def doc_upload(request):
# 获取文件对象
file_obj = request.FILES.get("avatars")
path = "./staffsys/static/img/" + file_obj.name
status = upload.upload(path=path, file_obj=file_obj)
res = {
'status': status
}
return JsonResponse(res)

2.utils

1
2
3
4
5
6
7
8
#upload.py
def upload(path, file_obj):
f = open(path, mode='wb')
#文件分块写入
for chunk in file_obj.chunks():
f.write(chunk)
f.close()
return True

3.模板层

1
2
3
4
5
<form method="post" enctype="multipart/form-data" action="/chart/upload/">
{% csrf_token %}
<input type="file" name="avatar">
<input type="submit" value="上传">
</form>

2.案例1:批量上传数据(基于Excel)

1.视图层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
def depart_upload(request):
"""批量上传文件"""
# 获取上传的文件对象
file_obj = request.FILES.get('exc')
"""------------------------------------上传文件到本地静态文件目录------------------------------------"""
# 直接打开excel并读取内容
wb = load_workbook(file_obj)
# 获取第一列
sheet = wb.worksheets[0]
# 读取第一行第一列
cell = sheet.cell(1, 3)
print(cell)
col_num = 1
depart_name = []
depart_leader = []
depart_num = []
# 循环获取每一列数据sheet.iter_cols(min_row=2, min_col=1):
# 循环获取每行数据sheet.iter_rows(min_row=2)
# for row in sheet.iter_rows(min_row=2):
for col in sheet.iter_cols(min_row=2, min_col=1):
for data in col:
if col_num == 1:
depart_name.append(data.value)
elif col_num == 2:
depart_leader.append(data.value)
else:
depart_num.append(data.value)
col_num += 1
data = {
'name': depart_name,
'leader': depart_leader,
'num': depart_num
}
status = True
row_num = len(data.get('name'))
for i in range(row_num):
exist = models.Department.objects.filter(title=data.get('name')[i]).exists()
if not exist:
models.Department.objects.create(title=data.get('name')[i], leader=data.get('leader')[i],
number=data.get('num')[i])
else:
status = False
res = {
'status': status,
'data': data,
}
return redirect('/depart/list/')

"""------------------------------------上传文件到本地静态文件目录------------------------------------"""
# path = "./staffsys/static/doc/" + file_obj.name
# if upload.upload(path=path, file_obj=file_obj):
# res = {
# 'status': True
# }
# return JsonResponse(res)
# return JsonResponse(res)

2.模板层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
{% extends 'layout.html' %}
{% block mytitle %}
<title>部门列表</title>
{% endblock %}
{% block mystyle %}
{% endblock %}
{% block info %}
<div class="container">
<div class="panel panel-default">
<div class="panel-heading"><i class="fa fa-list"></i>批量上传</div>
<div class="panel-body">
<form class="form-horizontal" method="post" action="/depart/upload/" enctype="multipart/form-data">
{% csrf_token %}
<div class="col-sm-12 form-group has-success has-feedback" style="width: 100%;margin: 0 auto;">
<div class="col-sm-6 text-center" style="margin: 0 auto;float: none">
<input type="file" multiple="" name="exc" class="form-control" id="batch_data"
aria-describedby="batch_dataStatus">
<span class="glyphicon glyphicon-upload form-control-feedback" aria-hidden="true"></span>
<span id="batch_dataStatus" class="sr-only">(success)</span>
<input class="btn btn-success" style="margin: 10px auto" type="submit" id="upload"
value="上传">
</div>
</div>
</form>
</div>
</div>

<div style="margin-bottom: 10px">
<a href="/depart/add/" class="btn btn-primary"><i class="fa fa-plus"></i>新建部门</a>
</div>

<div class="panel panel-info">
<div class="panel-heading"><i class="fa fa-list"></i> 部门列表</div>
<table class="table table-hover table-condensed table-bordered">
<thead>
<tr>
<th>部门ID</th>
<th>部门名称</th>
<th>部门负责人</th>
<th>部门人数</th>
<th>操作</th>
</tr>
</thead>
<tbody class="text-center">
{% for department in queryset %}
<tr>
<th scope="row">{{ department.id }}</th>
<td>{{ department.title }}</td>
<td>{{ department.leader }}</td>
<td>{{ department.number }}</td>
<td><a href="/depart/{{ department.id }}/edit/" class="btn btn-info btn-xs">编辑</a><a
href="/depart/delete/?nid={{ department.id }}"
class="btn btn-danger btn-xs">删除</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<div class="text-center">
<ul class="pagination pagination-xs">
{{ page_str }}
</ul>
</div>
</div>
{% endblock %}

3.案例2:混合数据(Form)

提交页面时:用户输入数据+文件(输入不能为空,报错)

1.Form.py表单模型

1
2
3
4
5
class FormUpload(bootstrapmodelform.BootStrapForm1):
boostrap_exclude_fields = ['avatar']
name = forms.CharField(label="用户名")
pwd = forms.CharField(label="密码", max_length=32)
avatar = forms.FileField(label="头像")

2.视图层

1
2
3
4
5
6
7
8
9
10
11
def form_upload(request):
if request.method == 'GET':
title = "Form表单上传"
form = FormUpload()
return render(request, "form_upload.html", {'form': form, 'title': title})
form = FormUpload(data=request.POST, files=request.FILES)
if form.is_valid():
print(form.cleaned_data)
# 读取到内容,根据需求合理处理每个字段信息
return JsonResponse({'status': True})
return render(request, "form_upload.html", {'form': form})

3.模板层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
{% extends 'layout.html' %} # 继承父模块的标识
{% block mytitle %}
<title>{{ title }}</title>
{% endblock %}
{% block mystyle %}
<style>
.input {
display: inline-block;
margin: 10px auto;
min-height: 50px;
width: 300px;
padding: 0 1rem;
color: #1e2732;
font-size: 15px;
border: 1px solid #5e4dcd;
border-radius: 6px;
background-color: transparent;
}

.button--submit {
display: block;
margin: 10px auto;
min-height: 50px;
padding: .5em 1em;
border: none;
border-radius: 6px;
background-color: #5e4dcd;
color: #fff;
font-size: 15px;
cursor: pointer;
transition: background-color .3s ease-in-out;
}

.button--submit:hover {
background-color: #5e5dcd;
}

.input:focus, .input:focus-visible {
border-color: #3898EC;
outline: none;
}
</style>
{% endblock %}
{% block info %}
<div>
<div class="container">
<div class="panel panel-info">
{% block actiontitle %}
<div class="panel-heading">{{ title }}</div>
{% endblock %}
<div class="panel-body">
{% block myform %}
<form class="input-group col-md-12" enctype="multipart/form-data" method="post" novalidate>
{% csrf_token %}
{% for item in form %}
<div class="form-group col-md-6">
<label>{{ item.label }}</label>
{{ item }}
<span style="color: #c12c1f"><strong>{{ item.errors.0 }}</strong></span>
</div>
{% endfor %}
<div class="form-group col-md-12">
<input class="button--submit " value="Subscribe" type="submit">
</div>
</form>
{% endblock %}
</div>
</div>
</div>
</div>
{% endblock %}

4.上传目录

在Django开发过程中有两个特殊的文件夹:

  • static:存放静态文件的路径,包括:CSS,JS,项目图片,项目插件等。
  • media:存放用户上传的数据的目录。
4.1启用media
  1. 配置urls.py

    1
    2
    3
    4
    5
    6
    7
    from django.urls import path, re_path
    from django.views.static import serve
    from django.conf import settings

    urlpatterns = [
    re_path(r'^media/(?P<path>.*)$', serve, {'document_root': settings.MEDIA_ROOT}, name='media'),
    ]
  2. 配置setting.py

    1
    2
    3
    4
    # 设置用户上传目录media目录
    import os
    MEDIA_ROOT = os.path.join(BASE_DIR, "media")
    MEDIA_URL = "/media/"

==路径位置==

image-20221219162711983

==浏览器访问media路径文件==

image-20221219162812492

5.案例3:混合数据(ModelForm)

1.模型层

1
2
3
4
5
6
class City(models.Model):
"""城市"""
name = models.CharField(verbose_name="名称", max_length=32)
count = models.IntegerField(verbose_name="人口")
# 本质上数据库也是CharField,自动保存数据,存的是文件路径
img = models.FileField(verbose_name="LOGO", max_length=128, upload_to="city/")

2.表单层

1
2
3
4
5
6
class ModelFormUpload(bootstrapmodelform.BootStrapModelForm1):
boostrap_exclude_fields = ['img']

class Meta:
model = models.City
fields = "__all__"

3.视图层

1
2
3
4
5
6
7
8
9
10
11
12
13
def modelform_upload(request):
"""modelform上传"""
title = "ModelForm上传"
if request.method == 'GET':
form = ModelFormUpload()
return render(request, 'modelform_upload.html', {"form": form, "title": title})
form = ModelFormUpload(data=request.POST, files=request.FILES)
if form.is_valid():
print(form.cleaned_data)
# modelform自动保存文件到模型层设置的目录,并且将字段+上传路径写入到数据库
form.save()
return JsonResponse({"status": True})
return render(request, 'modelform_upload.html', {"form": form, "title": title})

4.模板层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
{% extends 'layout.html' %} # 继承父模块的标识
{% block mytitle %}
<title>{{ title }}</title>
{% endblock %}
{% block mystyle %}
<style>
.input {
display: inline-block;
margin: 10px auto;
min-height: 50px;
width: 300px;
padding: 0 1rem;
color: #1e2732;
font-size: 15px;
border: 1px solid #5e4dcd;
border-radius: 6px;
background-color: transparent;
}

.button--submit {
display: block;
margin: 10px auto;
min-height: 50px;
padding: .5em 1em;
border: none;
border-radius: 6px;
background-color: #5e4dcd;
color: #fff;
font-size: 15px;
cursor: pointer;
transition: background-color .3s ease-in-out;
}

.button--submit:hover {
background-color: #5e5dcd;
}

.input:focus, .input:focus-visible {
border-color: #3898EC;
outline: none;
}
</style>
{% endblock %}
{% block info %}
<div>
<div class="container">
<div class="panel panel-info">
{% block actiontitle %}
<div class="panel-heading">{{ title }}</div>
{% endblock %}
<div class="panel-body">
{% block myform %}
<form class="input-group col-md-12" enctype="multipart/form-data" method="post" novalidate>
{% csrf_token %}
{% for item in form %}
<div class="form-group col-md-6">
<label>{{ item.label }}</label>
{{ item }}
<span style="color: #c12c1f"><strong>{{ item.errors.0 }}</strong></span>
</div>
{% endfor %}
<div class="form-group col-md-12">
<input class="button--submit " value="Subscribe" type="submit">
</div>
</form>
{% endblock %}
</div>
</div>
</div>
</div>
{% endblock %}

6.小结

  • 自己动手写

    1
    2
    file_obj = request.FILES.get("filename")
    ···
  • Form组件(表单验证)

    1
    2
    3
    4
    request.POST
    form = Form(data=request.POST,files=request.FILES)
    #保存需要自己保存
    file_obj = request.FILES.get("filename")
  • ModelForm组件(表单验证+自动保存)

    1
    2
    3
    4
    -media文件夹
    -models.py定义类包含文件字段
    # 本质上数据库也是CharField,自动保存数据,存的是文件路径
    img = models.FileField(verbose_name="LOGO", max_length=128, upload_to="city/")

14.Vue

Vue中文网

1.模板语法

Vue.js 使用了基于 HTML 的模板语法,允许开发者声明式地将 DOM 绑定至底层组件实例的数据。所有 Vue.js 的模板都是合法的 HTML,所以能被遵循规范的浏览器和 HTML 解析器解析。

在底层的实现上,Vue 将模板编译成虚拟 DOM 渲染函数。结合响应性系统,Vue 能够智能地计算出最少需要重新渲染多少组件,并把 DOM 操作次数减到最少。

如果你熟悉虚拟 DOM 并且偏爱 JavaScript 的原始力量,你也可以不用模板,直接写渲染 (render) 函数,使用可选的 JSX 语法。

1.1插值

文本

数据绑定最常见的形式就是使用“Mustache”语法 (双大括号) 的文本插值:

1
<span>Message: {{ msg }}</span>

Mustache 标签将会被替代为对应组件实例中 msg property 的值。无论何时,绑定的组件实例上 msg property 发生了改变,插值处的内容都会更新。

通过使用 v-once 指令,你也能执行一次性地插值,当数据改变时,插值处的内容不会更新。但请留心这会影响到该节点上的其它数据绑定:

1
<span v-once>这个将不会改变: {{ msg }}</span>

注:绑定一个纯文本

原始 HTML

双大括号会将数据解释为普通文本,而非 HTML 代码。为了输出真正的 HTML,你需要使用v-html 指令

1
2
<p>Using mustaches: {{ rawHtml }}</p>
<p>Using v-html directive: <span v-html="rawHtml"></span></p>

注:绑定一个动态的html标签

Attribute

Mustache 语法不能在 HTML attribute 中使用,然而,可以使用 v-bind 指令

1
2
<div v-bind:id="dynamicId"></div>
<div :id="dynamicId"></div>

如果绑定的值是 nullundefined,那么该 attribute 将不会被包含在渲染的元素上。

对于布尔 attribute (它们只要存在就意味着值为 true),v-bind 工作起来略有不同,在这个例子中:

1
<button v-bind:disabled="isButtonDisabled">按钮</button>

如果 isButtonDisabled 的值是 truthy[1],那么 disabled attribute 将被包含在内。如果该值是一个空字符串,它也会被包括在内,与 <button disabled=""> 保持一致。对于其他错误的值,该 attribute 将被省略。

注:绑定一个动态的属性

使用 JavaScript 表达式

迄今为止,在我们的模板中,我们一直都只绑定简单的 property 键值。但实际上,对于所有的数据绑定,Vue.js 都提供了完全的 JavaScript 表达式支持。

1
2
3
4
5
6
7
8
9
{{ number + 1 }}

{{ message + " World" }}

{{ ok ? 'YES' : 'NO' }}

{{ message.split('').reverse().join('') }}

<div v-bind:id="'list-' + id"></div>

这些表达式会在当前活动实例的数据作用域下作为 JavaScript 被解析。有个限制就是,每个绑定都只能包含单个表达式,所以下面的例子都不会生效。

1
2
3
4
5
<!--  这是语句,不是表达式:-->
{{ var a = 1 }}

<!-- 流控制也不会生效,请使用三元表达式 -->
{{ if (ok) { return message } }}

1.2指令

指令 (Directives) 是带有 v- 前缀的特殊 attribute。指令 attribute 的值预期是单个 JavaScript 表达式 (v-forv-on 是例外情况,稍后我们再讨论)。指令的职责是,当表达式的值改变时,将其产生的连带影响,响应式地作用于 DOM。回顾我们在介绍中看到的例子:

1
2
3
   <p v-if="flag">我是真悟空</p>
<p v-else>我是假猴子</p>
<p v-show:"flag">我是真猴子</p>

这里,v-if 指令(条件显示必定显示一个)将根据表达式 flag 的值的真假来插入/移除 <p> 元素;flag为假时v-else标签将显示。v-show根据条件只显示或不显示(等价于没有v-else时的v-if)。

#参数

一些指令能够接收一个“参数”,在指令名称之后以冒号表示。例如,v-bind 指令可以用于响应式地更新 HTML attribute:

1
<a v-bind:href="url"> ... </a>

在这里 href 是参数,告知 v-bind 指令将该元素的 href attribute 与表达式 url 的值绑定。

另一个例子是 v-on 指令,它用于监听 DOM 事件:

1
<a v-on:click="doSomething"> ... </a>

在这里参数是监听的事件名。我们也会更详细地讨论事件处理。

#动态参数

也可以在指令参数中使用 JavaScript 表达式,方法是用方括号括起来:

1
2
3
4
<!--
注意,参数表达式的写法存在一些约束,如之后的“对动态参数表达式的约束”章节所述。
-->
<a v-bind:[attributeName]="url"> ... </a>

这里的 attributeName 会被作为一个 JavaScript 表达式进行动态求值,求得的值将会作为最终的参数来使用。例如,如果你的组件实例有一个 data property attributeName,其值为 "href",那么这个绑定将等价于 v-bind:href

同样地,你可以使用动态参数为一个动态的事件名绑定处理函数:

1
<a v-on:[eventName]="doSomething"> ... </a>

在这个示例中,当 eventName 的值为 "focus" 时,v-on:[eventName] 将等价于 v-on:focus

#修饰符

修饰符 (modifier) 是以半角句号 . 指明的特殊后缀,用于指出一个指令应该以特殊方式绑定。例如,.prevent 修饰符告诉 v-on 指令对于触发的事件调用 event.preventDefault()

1
<form v-on:submit.prevent="onSubmit">...</form>

在接下来对 v-onv-for 等功能的探索中,你会看到修饰符的其它例子。

v-on与v-show区别与联系

v-bind:是用来绑定属性的,v-bind使用的时候一般写在data里面。
v-on:用来绑定事件的,v-on使用的时候一般写在methods方法里面

1.3条件渲染

1v-if

v-if 指令用于条件性地渲染一块内容。这块内容只会在指令的表达式返回 truthy 值的时候被渲染。

1
<h1 v-if="awesome">Vue is awesome!</h1>

也可以用 v-else 添加一个“else 块”:

1
2
<h1 v-if="awesome">Vue is awesome!</h1>
<h1 v-else>Oh no 😢</h1>
2<template> 元素上使用 v-if 条件渲染分组

因为 v-if 是一个指令,所以必须将它添加到一个元素上。但是如果想切换多个元素呢?此时可以把一个 <template> 元素当做不可见的包裹元素,并在上面使用 v-if。最终的渲染结果将不包含 <template> 元素。

1
2
3
4
5
<template v-if="ok">
<h1>Title</h1>
<p>Paragraph 1</p>
<p>Paragraph 2</p>
</template>
3v-else

你可以使用 v-else 指令来表示 v-if 的“else 块”:

1
2
3
4
5
6
<div v-if="Math.random() > 0.5">
Now you see me
</div>
<div v-else>
Now you don't
</div>

v-else 元素必须紧跟在带 v-if 或者 v-else-if 的元素的后面,否则它将不会被识别。

4v-else-if

v-else-if,顾名思义,充当 v-if 的“else-if 块”,并且可以连续使用:

1
2
3
4
5
6
7
8
9
10
11
12
<div v-if="type === 'A'">
A
</div>
<div v-else-if="type === 'B'">
B
</div>
<div v-else-if="type === 'C'">
C
</div>
<div v-else>
Not A/B/C
</div>

v-else 的用法类似,v-else-if 也必须紧跟在带 v-if 或者 v-else-if 的元素之后。

5v-show

另一个用于条件性展示元素的选项是 v-show 指令。用法大致一样:

1
<h1 v-show="ok">Hello!</h1>

不同的是带有 v-show 的元素始终会被渲染并保留在 DOM 中。v-show 只是简单地切换元素的 CSS property display

注意,v-show 不支持 <template> 元素,也不支持 v-else

6v-if vs v-show

v-if 是“真正”的条件渲染,因为它会确保在切换过程中,条件块内的事件监听器和子组件适当地被销毁和重建。

v-if 也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。

相比之下,v-show 就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换。

一般来说,v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件很少改变,则使用 v-if 较好。

7v-ifv-for 一起使用

不推荐同时使用 v-ifv-for。请查阅风格指南以获取更多信息。

v-ifv-for 一起使用时,v-if 具有比 v-for 更高的优先级。请查阅列表渲染指南以获取详细信息。

1.4列表渲染

1.用 v-for 把一个数组对应为一组元素

我们可以用 v-for 指令基于一个数组来渲染一个列表。v-for 指令需要使用 item in items 形式的特殊语法,其中 items 是源数据数组,而 item 则是被迭代的数组元素的别名

1
2
3
4
5
<ul id="array-rendering">
<li v-for="item in items">
{{ item.message }}
</li>
</ul>
1
2
3
4
5
6
7
Vue.createApp({
data() {
return {
items: [{ message: 'Foo' }, { message: 'Bar' }]
}
}
}).mount('#array-rendering')

v-for 块中,我们可以访问所有父作用域的 property。v-for 还支持一个可选的第二个参数,即当前项的索引。

1
2
3
4
5
<ul id="array-with-index">
<li v-for="(item, index) in items">
{{ parentMessage }} - {{ index }} - {{ item.message }}
</li>
</ul>
1
2
3
4
5
6
7
8
Vue.createApp({
data() {
return {
parentMessage: 'Parent',
items: [{ message: 'Foo' }, { message: 'Bar' }]
}
}
}).mount('#array-with-index')

你也可以用 of 替代 in 作为分隔符,因为它更接近 JavaScript 迭代器的语法:

1
<div v-for="item of items"></div>
2.在-v-for-里使用对象在 v-for 里使用对象

你也可以用 v-for 来遍历一个对象的 property。

1
2
3
4
5
<ul id="v-for-object" class="demo">
<li v-for="value in myObject">
{{ value }}
</li>
</ul>
1
2
3
4
5
6
7
8
9
10
11
Vue.createApp({
data() {
return {
myObject: {
title: 'How to do lists in Vue',
author: 'Jane Doe',
publishedAt: '2016-04-10'
}
}
}
}).mount('#v-for-object')

你也可以提供第二个的参数为 property 名称 (也就是键名 key):

1
2
3
<li v-for="(value, name) in myObject">
{{ name }}: {{ value }}
</li>

还可以用第三个参数作为索引:

1
2
3
<li v-for="(value, name, index) in myObject">
{{ index }}. {{ name }}: {{ value }}
</li>

在遍历对象时,会按 Object.keys() 的结果遍历,但是不能保证它在不同 JavaScript 引擎下的结果都一致。

3.维护状态

当 Vue 正在更新使用 v-for 渲染的元素列表时,它默认使用“就地更新”的策略。如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序,而是就地更新每个元素,并且确保它们在每个索引位置正确渲染。

这个默认的模式是高效的,但是只适用于不依赖子组件状态或临时 DOM 状态 (例如:表单输入值) 的列表渲染输出

为了给 Vue 一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,你需要为每项提供一个唯一 key attribute:

1
2
3
<div v-for="item in items" :key="item.id">
<!-- content -->
</div>

建议尽可能在使用 v-for 时提供 key attribute,除非遍历输出的 DOM 内容非常简单,或者是刻意依赖默认行为以获取性能上的提升。

因为它是 Vue 识别节点的一个通用机制,key 并不仅与 v-for 特别关联。后面我们将在指南中看到,它还具有其它用途。

1.5事件处理

1.监听事件

我们可以使用 v-on 指令 (通常缩写为 @ 符号) 来监听 DOM 事件,并在触发事件时执行一些 JavaScript。用法为 v-on:click="methodName" 或使用快捷方式 @click="methodName"

例如:

1
2
3
4
<div id="basic-event">
<button @click="counter += 1">Add 1</button>
<p>The button above has been clicked {{ counter }} times.</p>
</div>
1
2
3
4
5
6
7
Vue.createApp({
data() {
return {
counter: 0
}
}
}).mount('#basic-event')
2.内联处理器中的方法

除了直接绑定到一个方法,也可以在内联 JavaScript 语句中调用方法:

1
2
3
4
5
6
7
8
9
10
<div id="inline-handler">
<button @click="say('hi')">Say hi</button>
<button @click="say('what')">Say what</button>
<ul>
<li>列表渲染</li>
<li @click="send(item.title)" v-for="(item, index) in items" :key="item.id">
{{ item.title }}
</li>
</ul>
</div>
1
2
3
4
5
6
7
8
9
10
Vue.createApp({
methods: {
say(message) {
alert(message)
},
send (data) {
console.log(data);
},
}
}).mount('#inline-handler')

有时也需要在内联语句处理器中访问原始的 DOM 事件。可以用特殊变量 $event 把它传入方法:

1
2
3
<button @click="warn('Form cannot be submitted yet.', $event)">
Submit
</button>
1
2
3
4
5
6
7
8
9
10
// ...
methods: {
warn(message, event) {
// 现在可以访问到原生事件
if (event) {
event.preventDefault()
}
alert(message)
}
}
3.多事件处理器

事件处理程序中可以有多个方法,这些方法由逗号运算符分隔:

1
2
3
4
<!-- 这两个 one() 和 two() 将执行按钮点击事件 -->
<button @click="one($event), two($event)">
Submit
</button>
1
2
3
4
5
6
7
8
9
// ...
methods: {
one(event) {
// 第一个事件处理器逻辑...
},
two(event) {
// 第二个事件处理器逻辑...
}
}

1.6表单输入绑定

1.基础用法

你可以用 v-model 指令在表单 <input><textarea><select> 元素上创建双向数据绑定。它会根据控件类型自动选取正确的方法来更新元素。尽管有些神奇,但 v-model 本质上不过是语法糖。它负责监听用户的输入事件来更新数据,并在某种极端场景下进行一些特殊处理。

提示

v-model 会忽略所有表单元素的 valuecheckedselected attribute 的初始值而总是将当前活动实例的数据作为数据来源。你应该通过 JavaScript 在组件的 data 选项中声明初始值。

v-model 在内部为不同的输入元素使用不同的 property 并抛出不同的事件:

  • text 和 textarea 元素使用 value property 和 input 事件;
  • checkbox 和 radio 使用 checked property 和 change 事件;
  • select 字段将 value 作为 prop 并将 change 作为事件。

提示

对于需要使用输入法 (如中文、日文、韩文等) 的语言,你会发现 v-model 不会在输入法组织文字过程中得到更新。如果你也想响应这些更新,请使用 input 事件监听器和 value 绑定,而不是使用 v-model

2.文本 (Text)
1
2
<input v-model="message" placeholder="edit me" />
<p>Message is: {{ message }}</p>
3.多行文本 (Textarea)
1
2
3
4
<span>Multiline message is:</span>
<p style="white-space: pre-line;">{{ message }}</p>
<br />
<textarea v-model="message" placeholder="add multiple lines"></textarea>
1
2
3
4
5
<!-- bad -->
<textarea>{{ text }}</textarea>

<!-- good -->
<textarea v-model="text"></textarea>
4.复选框 (Checkbox)

单个复选框,绑定到布尔值:

1
2
<input type="checkbox" id="checkbox" v-model="checked" />
<label for="checkbox">{{ checked }}</label>

多个复选框,绑定到同一个数组:

1
2
3
4
5
6
7
8
9
10
<div id="v-model-multiple-checkboxes">
<input type="checkbox" id="jack" value="Jack" v-model="checkedNames" />
<label for="jack">Jack</label>
<input type="checkbox" id="john" value="John" v-model="checkedNames" />
<label for="john">John</label>
<input type="checkbox" id="mike" value="Mike" v-model="checkedNames" />
<label for="mike">Mike</label>
<br />
<span>Checked names: {{ checkedNames }}</span>
</div>
1
2
3
4
5
6
7
Vue.createApp({
data() {
return {
checkedNames: []
}
}
}).mount('#v-model-multiple-checkboxes')
5.单选框 (Radio)
1
2
3
4
5
6
7
8
9
<div id="v-model-radiobutton">
<input type="radio" id="one" value="One" v-model="picked" />
<label for="one">One</label>
<br />
<input type="radio" id="two" value="Two" v-model="picked" />
<label for="two">Two</label>
<br />
<span>Picked: {{ picked }}</span>
</div>
1
2
3
4
5
6
7
Vue.createApp({
data() {
return {
picked: ''
}
}
}).mount('#v-model-radiobutton')
6.选择框 (Select)

单选时:

1
2
3
4
5
6
7
8
9
<div id="v-model-select" class="demo">
<select v-model="selected">
<option disabled value="">Please select one</option>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
<span>Selected: {{ selected }}</span>
</div>
1
2
3
4
5
6
7
Vue.createApp({
data() {
return {
selected: ''
}
}
}).mount('#v-model-select')

多选时 (绑定到一个数组):

1
2
3
4
5
6
7
<select v-model="selected" multiple>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
<br />
<span>Selected: {{ selected }}</span>
7.值绑定

对于单选按钮,复选框及选择框的选项,v-model 绑定的值通常是静态字符串 (对于复选框也可以是布尔值):

1
2
3
4
5
6
7
8
9
10
<!-- 当选中时,`picked` 为字符串 "a" -->
<input type="radio" v-model="picked" value="a" />

<!-- `toggle` 为 true 或 false -->
<input type="checkbox" v-model="toggle" />

<!-- 当选中第一个选项时,`selected` 为字符串 "abc" -->
<select v-model="selected">
<option value="abc">ABC</option>
</select>

但是有时我们可能想把值绑定到当前活动实例的一个动态 property 上,这时可以用 v-bind 实现,此外,使用 v-bind 可以将输入值绑定到非字符串。

8.复选框 (Checkbox)
1
<input type="checkbox" v-model="toggle" true-value="yes" false-value="no" />
1
2
3
4
// when checked:
vm.toggle === 'yes'
// when unchecked:
vm.toggle === 'no'
9.单选框 (Radio)
1
<input type="radio" v-model="pick" v-bind:value="a" />
1
2
// 当选中时
vm.pick === vm.a
10.选择框选项 (Select Options)
1
2
3
4
<select v-model="selected">
<!-- 内联对象字面量 -->
<option :value="{ number: 123 }">123</option>
</select>
1
2
3
// 当被选中时
typeof vm.selected // => 'object'
vm.selected.number // => 123

1.7修饰符

1..lazy

在默认情况下,v-model 在每次 input 事件触发后将输入框的值与数据进行同步 (除了上述输入法组织文字时)。你可以添加 lazy 修饰符,从而转为在 change 事件_之后_进行同步:

1
2
<!-- 在“change”时而非“input”时更新 -->
<input v-model.lazy="msg" >
2..number

如果想自动将用户的输入值转为数值类型,可以给 v-model 添加 number 修饰符:

1
<input v-model.number="age" type="number" />

这通常很有用,因为即使在 type="number" 时,HTML 输入元素的值也总会返回字符串。如果这个值无法被 parseFloat() 解析,则会返回原始的值。

3..trim

如果要自动过滤用户输入的首尾空白字符,可以给 v-model 添加 trim 修饰符:

1
<input v-model.trim="msg" />

2.组件基础

单文件组件(又名*.vue文件,缩写为SFC)是一种特殊的文件格式,它允许将Vue组件的模板、逻辑与样式封装在单个文件中。

1.新建组件

2.加载组件

  • 引入组件:import MyComponent from './components/MyComponent.vue';在App.vue根组件中引入

  • 挂载组件:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    //在js中
    export default {
    name: 'App',
    components: {
    HelloWorld,
    Form,
    MyComponent,
    }
    }
  • 显示组件:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
      <template>
    <MyComponent />
    <my-component />//推荐这种方式
    </template>

    >
    ```vue
    <!-- scoped:如果在style中添加此属性,则该样式只对该组件生效,否则对全局生效 -->
    <style scoped>
    h3 {
    color: aquamarine;
    }
    </style>

3.组件的组织

通常一个应用会以一颗嵌套的组建树的形式来组织。

3.Props组件交互

组件与组件之间是需要存在交互的,否则完全没有关系,组件的意义就很小了。

Prop是你可以在组件上注册的一些自定义属性attribute。

==app.vue(传递title和age属性值)==

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<template>
<my-component :title="title" :age="age" />
</template>

<script>
import HelloWorld from './components/HelloWorld.vue';
import Form from './components/Form.vue';
import MyComponent from './components/MyComponent.vue';


export default {
name: 'App',
components: {
HelloWorld,
Form,
MyComponent,
},
data () {
return {
title: 'Props',
age: '20',
}
}
}
</script>

==MyComponent.vue==

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<template>
<h3>我的组件</h3>
<h3>Prop传递数据</h3>
<p>{{ title }}</p>
<p>{{ age }}</p>
</template>
<script>
export default {
name: "MyComponent",
props: {
title: {
type: String,
default: "传递失败",
},
age: {
type: Number,
default: 0,
}
}
}
</script>

<!-- scoped:如果在style中添加此属性,则该样式只对该组件生效,否则对全局生效 -->
<style scoped>
h3 {
color: aquamarine;
}
</style>

1.Prop类型

Prop传递参数其实是没有类型限制的

1
2
3
4
5
6
7
8
props: {
title: String,
age: Number,
isPublished: Boolean,
commentIds: Array,
author: Object,
callback: Function
}

温馨提示

数据类型为数组或者对象的时候,默认值是需要返回工厂模式(使用函数进行返回)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
  <ul>
<li v-for="(item, index) in names" :key="index">{{ item }}</li>
</ul>

<script>
export default {
name: "MyComponent",
props: {
names: {
type: Array,
// 数组和对象必须使用函数进行返回
default: function () {
return []
}
}
}
}
</script>

4.自定义事件组件交互

自定义事件可以在组件中反向传递数据,prop可以将数据从父组件传递到子组件,那么反向如何操作呢,可以利用自定义时间实现$emit

==app.vue==

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<template>
<my-component @onEvent="getmsg" />
<p>{{ msg }}</p>
</template>

<script>
import MyComponent from './components/MyComponent.vue';

export default {
name: 'App',
components: {
MyComponent,
},
data () {
return {
msg: "",
}
},
methods: {
getmsg (data) {
console.log(data);
this.msg = data;
}
}
}
</script>

<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
/* margin-top: 60px; */
margin: 60px auto;
}
</style>

==MyComponent.vue==

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<template>
<h3>自定义事件传递数据</h3>
<button @click="sendmsg">点击传递</button>
</template>
<script>
export default {
name: "MyComponent",
data () {
return {
msg: "字数据传向父",
}
},
methods: {
sendmsg () {
// 参数1:字符串;
// 参数2:传递的数据
this.$emit("onEvent", this.msg)
}

}
}
</script>

<!-- scoped:如果在style中添加此属性,则该样式只对该组件生效,否则对全局生效 -->
<style scoped>
h3 {
color: aquamarine;
}
</style>

5.组件生命周期

每个组件在被创建时都要经过一系列的初始化过程–例如,需要设置数据监听、编译模板、将实例挂载到DOM并在数据变化时更新DOM等。同时在这个过程中也会运行一些叫做生命周期钩子的函数,这给了用户在不同阶段添加自己的代码的机会。

分类:

  1. 创建时:beforeCreatecreated
  2. 渲染时:beforeMountmounted
  3. 更新时:beforeUpdateupdated
  4. 卸载时:beforeUnmountunmounted

6.Vue引入第三方

Swiper开源强大的触摸滑动插件。

安装指定版本:npm install --save swiper@8.1.6

案例1:首页轮播图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<template>
<swiper :modules="modules" navigation :pagination="{ clickable: true }">
<swiper-slide><img src="https://picsum.photos/id/123/900/400" alt="1"></swiper-slide>
<swiper-slide><img src="https://picsum.photos/id/88/900/400" alt="2"></swiper-slide>
<swiper-slide><img src="https://picsum.photos/id/13/900/400" alt="3"></swiper-slide>
</swiper>
</template>

<script>
import { Navigation, Pagination } from 'swiper';
import { Swiper, SwiperSlide } from 'swiper/vue';
import 'swiper/css';
import 'swiper/css/navigation';
import 'swiper/css/pagination';

export default {
name: 'HelloWorld',
components: {
Swiper,
SwiperSlide,
},
setup () {
return {
modules: [Navigation, Pagination],
};
},
data () {
return {

}
},
methods: {

}
}
</script>

7.Axios网络请求

Axios是一个基于promise的网络请求库

安装npm install --save axios

1.引入

组件中引入:import axios from "axios"

全局引入:

1
2
3
4
5
6
7
8
import axios form "axios"

const app = createApp(App);
app.config.globalProperties.$axios = axios
app.mount('#app')

//在组件中调用
this.$axios

2.网络请求示例

get请求
1
2
3
4
5
6
7
8
9
mounted () {
axios({
method: 'get',
url: 'http://iwenwiki.com/api/blueberrypai/getChengpinDetails.php'
}).then(res => {
console.log(res.data);
this.chengpin = res.data.chengpinDetails[0];
})
}

==get快捷方式==

1
2
3
axios.get("http://iwenwiki.com/api/blueberrypai/getChengpinDetails.php").then(res => {
console.log(res.data);
})
post请求

温馨提示

  1. 安装依赖:npm install --save querystring
  2. 转换参数格式:qs.stringify()(将字符串格式转为对象)
1
2
3
4
5
6
7
8
9
10
11
12
// post请求方式
axios({
method: 'post',
url: 'http://iwenwiki.com/api/blueberrypai/login.php',
data: querystring.stringify({
user_id: 'iwen@qq.com',
password: 'iwen123',
verification_code: 'crfvw'
})
}).then(res => {
console.log(res.data);
})

==post快捷方式==

1
2
3
4
5
6
7
axios.post("http://iwenwiki.com/api/blueberrypai/login.php", querystring.stringify({
user_id: 'iwen@qq.com',
password: 'iwen123',
verification_code: 'crfvw'
})).then(res => {
console.log(res.data);
})

3.axios网络请求封装

日常应用过程中,一个项目中会有很多网络请求,一般采取的方案是将网络请求封装起来。

src目录下创建文件夹utils,并创建文件request,用来存储网络请求对象axios

4.网络请求跨域解决方案

出于浏览器的同源策略限制。同源策略(Sameoriginpolicy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。同源策略会阻止一个域的。javascript脚本和另外一个域的内容进行交互。所谓同源(即指在同一个域)就是两个页面具有相同的协议(protocol),主机(host)和端口号(port。

提示:当一个请求url的**协议、域名、端口**三者之间任意一个与当前页面url不同即为跨域。

1.主流的解决方案
  1. 后台解决:cors
  2. 前台解决:proxy
1
2
3
4
5
6
7
8
devServer: {
proxy: {
'/api': {
target: 'http://iwenwiki.com',//填写需要跨域请求的网址包括协议和域名端口
changeOrigin: true
}
}
}

温馨提示

配置完成后,axios请求的地址直接用域名后的子地址即可,且需要重启服务器才生效。

8.路由配置(vue-router)

在vue中,我们可以通过vue-router路由管理页面之间的关系

Vue Router是Vue.js的官方路由。它与Vue.js核心深度集成,让用Vue.js构建单页应用变得轻而易举。

1.在Vue中引入路由

第一步:安装路由npm install --save vue-router

第二步:新建路由配置文件

第三步:配置独立的路由文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
/*
* @Author: Alleyf 3035581811@qq.com
* @Github: https://github.com/Alleyf
* @QQ: 3035581811
* @Signature: You know more,you know less
* @Date: 2022-12-26 09:21:10
* @LastEditors: Alleyf 3035581811@qq.com
* @LastEditTime: 2022-12-26 09:48:38
* @FilePath: \MedocSystem\vue-medocsystem\src\router\index.js
* Copyright (c) 2022 by Alleyf 3035581811@qq.com, All Rights Reserved.
*/
import {createRouter,createWebHashHistory} from 'vue-router'
import Home from '../views/Home'
import About from '../views/About'

// 配置信息中需要页面的相关参数

const routes = [
{
path: '/', //访问路径
component: Home, //对应的页面
},
{
path: '/about',
component: About,
}
]



const router = createRouter({
/* createWebHashHistory
Home:http://localhost:8080/#/
About:http://localhost:8080/#/about
原理:a标签锚点连接

createWebHistory
Home:http://localhost:8080/
About:http://localhost:8080/about
此种方式,需要后台配合做重定向,否则会出现404问题

原理:H5 pushState()
*/
history: createWebHashHistory(),
routes
})

export default router;

温馨提示

createWebHashHistory
Home:http://localhost:8080/#/
About:http://localhost:8080/#/about
原理:a标签锚点连接

createWebHistory
Home:http://localhost:8080/
About:http://localhost:8080/about
此种方式,需要后台配合做重定向,否则会出现404问题

原理:H5 pushState()

第四步:main.js中使用路由

1
2
3
4
5
6
7
8
9
10
11
import { createApp } from 'vue'
import App from './App.vue'
import './registerServiceWorker'
import axios from "axios"
import router from "./router"

// 将axios挂载到全局
const app = createApp(App);
app.config.globalProperties.$axios = axios
app.use(router)
app.mount('#app')

第五步:App.vue中设置路由入口

1
2
3
4
5
6
<template>
<!-- 路由的显示入口 -->
<router-link to="/">首页</router-link> |
<router-link to="/about">关于</router-link>
<router-view></router-view>
</template>

2.路由传递参数

页面携带参数跳转非常常见

  • 第一步:在路由配置中指定参数key

    1
    2
    3
    4
    5
    6
    //此处参数名为name
    {
    path: '/newsdetails/:name',
    name: 'newsdetails',
    component: ()=>import("../views/NewsDetails.vue") //异步加载
    },
  • 第二步:在页面中的路由链接中携带参数

    1
    2
    3
    4
    5
    6
    7
    8
    <template>
    <h2>新闻</h2>
    <ul>
    <li><Router-Link to="/newsdetails/百度">百度新闻</Router-Link></li>
    <li><Router-Link to="/newsdetails/网易">网易新闻</Router-Link></li>
    <li><Router-Link to="/newsdetails/头条">头条新闻</Router-Link></li>
    </ul>
    </template>
  • 第三步:在跳转页面获取参数

    1
    2
    3
    4
    <template>
    <h3>新闻详情</h3>
    <p>{{ $route.params.name }}</p>
    </template>

3.嵌套路由配置

  • 第一步:创建子路由要加载的页面

  • 第二步:index.js配置子路由

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    {
    path: '/about',
    name: 'about',
    component: ()=>import("../views/About.vue"), //异步加载
    redirect: "/about/us",
    children: [
    {
    path: 'us',
    name: 'us',
    component: ()=>import("../views/about/AboutUs.vue"),
    },
    {
    path: 'info',
    name: 'info',
    component: ()=>import("../views/about/AboutInfo.vue"),
    }
    ]
    },
  • 第三步:添加子路由跳转链接并指定子路由显示位置

    1
    2
    3
    4
    5
    6
    7
    <template>
    <div class="about">
    <Router-Link to="/about/us">关于我们</Router-Link> |
    <Router-Link to="/about/info">关于信息</Router-Link>
    <Router-View></Router-View>
    </div>
    </template>
  • 第四步:重定向配置默认显示页面(在index.js中父路由中配置)

    1
    redirect: "/about/us",

9.Vue状态管理(Vuex)

vuex是一个专门为Vue.js应用程序开发的状态管理模式+库。它采用集中式存储管理应用的所有组件的状态。

简单来说,状态给管理可以理解成为了更方便的管理组件之间的数据交互,提供了一个集中式的管理方案,任何组件都可以按照指定的方式进行读取和改变数据。

1.引入Vuex的步骤

第一步:安装Vuex cnpm install --save vuex

第二步:新建store文件夹并新建index.js文件

第三步:配置Vuex文件

1
2
3
4
5
6
7
8
9
10
import {createStore} from "vuex"


//Vuex的核心作用就是帮我们管理组件之间的状态的
export default createStore({
//所有状态(公共数据)都放在这里
state: {
counter: 0,
}
})

第四步:在主文件中引入Vuex

1
2
import store from "./store"
app.use(store)

第五步:在组件中读取状态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//第一种读取方法
<template>
<p>counter:{{ $store.state.counter }}</p>
</template>
//第二种读取方法
<template>
<li>counter:{{ counter }}</li>
</template>
<script>
//vuex提供的state快捷读取方式
import { mapState } from 'vuex';

export default {
//专门用来读取vuex中的数据
computed: {
...mapState(["counter"]),
}
}
</script>

2.状态管理核心

常用的核心概念包含:State,Getter,Mutation,Action

1.Getter

对vuex的数据进行过滤

配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import {createStore} from "vuex"


//Vuex的核心作用就是帮我们管理组件之间的状态的
export default createStore({
//所有状态(公共数据)都放在这里
state: {
counter: 0,
},
getters: {
getCounter(state){
return state.counter > 0 ? state.counter : "counter数据异常"
}
}
})

vue用法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<template>
<h2>新闻</h2>
<ul>
<li>counter:{{ getCounter }}</li>
<li>counter={{ $store.getters.getCounter }}</li>
<li><Router-Link to="/newsdetails/百度">百度新闻</Router-Link></li>
<li><Router-Link to="/newsdetails/网易">网易新闻</Router-Link></li>
<li><Router-Link to="/newsdetails/头条">头条新闻</Router-Link></li>
</ul>
</template>

<script>
import { mapGetters } from 'vuex';

export default {
computed: {
...mapGetters(["getCounter"]),
}
}
</script>
2.Mutation

更改Vuex的store中的状态的唯一方法是提交mutation。Vuex中的mutation非常类似与事件:每个mutation都有一个字符串的事件类型(type)和一个回调函数(handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受state作为第一个参数。

配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import {createStore} from "vuex"


//Vuex的核心作用就是帮我们管理组件之间的状态的
export default createStore({
//所有状态(公共数据)都放在这里
state: {
counter: 0,
},
getters: {
getCounter(state){
return state.counter > 0 ? state.counter : "counter数据异常"
}
},
mutations: {
addCounter(state,num){
state.counter += num;
}
}
})

vue用法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<template>
<h2>新闻</h2>
<ul>
<li>counter:{{ getCounter }}</li>
<li>counter={{ $store.getters.getCounter }}</li>
<li><Router-Link to="/newsdetails/百度">百度新闻</Router-Link></li>
<li><Router-Link to="/newsdetails/网易">网易新闻</Router-Link></li>
<li><Router-Link to="/newsdetails/头条">头条新闻</Router-Link></li>
</ul>
<div>
<button @click="addCounterHandler">加</button>
</div>
</template>

<script>
import { mapGetters, mapMutations } from 'vuex';

export default {
computed: {
...mapGetters(["getCounter"]),
},
methods: {
...mapMutations(["addCounter"]),
addCounterHandler () {
// 固定调用方式
this.addCounter(20);
// this.$store.commit("addCounter", 5)
}
}
}
3.action

action类似于mutation,不同在于:

  • action提交的是mutation,而不是直接变更状态。
  • action可以包含任意异步操作
  • 主要用于异步请求处理数据。

配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import axios from "axios";
import {createStore} from "vuex"


//Vuex的核心作用就是帮我们管理组件之间的状态的
export default createStore({
//所有状态(公共数据)都放在这里
state: {
counter: 0,
},
getters: {
getCounter(state){
return state.counter > 0 ? state.counter : "counter数据异常"
}
},
mutations: {
addCounter(state,num){
state.counter += num;
}
},
// 为异步操作准备
actions: {
asyncAddCounter({commit}){
axios.get("http://iwenwiki.com/api/generator/list.php").then(res=>{
// 以下是使用方式
commit("addCounter",res.data[0]);
})
}
}
})

vue用法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<template>
<h2>新闻</h2>
<ul>
<li>counter:{{ getCounter }}</li>
<li>counter={{ $store.getters.getCounter }}</li>
<li><Router-Link to="/newsdetails/百度">百度新闻</Router-Link></li>
<li><Router-Link to="/newsdetails/网易">网易新闻</Router-Link></li>
<li><Router-Link to="/newsdetails/头条">头条新闻</Router-Link></li>
</ul>
<div>
<button @click="addCounterHandler">同步加</button>
<br>
<button @click="asyncAddCounterHandler">异步加</button>
</div>
</template>

<script>
import { mapGetters, mapMutations } from 'vuex';

export default {
computed: {
...mapGetters(["getCounter"]),
},
methods: {
...mapMutations(["addCounter"]),
addCounterHandler () {
// 固定调用方式
this.addCounter(20);
// this.$store.commit("addCounter", 5)
},
asyncAddCounterHandler () {
this.$store.dispatch("asyncAddCounter");
}
}
}
</script>

<style>
ul li {
text-align: center;
}
</style>

10.vue3新特性

1.组合式API

1.ref或者reactive

在2.x中通过组建data的方法定义一些当前组件的数据,可以代替data定义数据并显示。

setup(){}里既可以定义数据,亦可以定义响应事件(函数),从而取代datamethods

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<template>
<div>
<p>{{ msg }}</p>
<ul>
<li v-for="(item, index) in names.list" :key="index">{{ item }}</li>
</ul>
<button @click="changeMsgHandler">修改数据</button>
</div>
</template>

<script>
import { mapGetters, mapMutations } from 'vuex';
import { ref, reactive } from "vue"



export default {
setup () {
// ref:定义简单数据
const msg = ref("i am a message");
// reactive:定义复杂数据(数组、对象等)
const names = reactive({
list: ["one", "two", "three"]
});

function changeMsgHandler () {
// 通过msg.value去修改数据
msg.value = "我是新消息";
}

return {
msg,
names,
changeMsgHandler,
}
},
}
2.setup中使用props和context

在2.x中,组件的方法可以通过this获取当前组件的实例,并执行data变量的修改,方法的调用,组件的通信等等,但是在3.x中,setup()在beforeCreate和created时机就已调用,无法使用和2.x一样的this,但是可以通过接收setup(props,ctx)的方法,获取到当前组件的实例和props。

==父组件(App.vue)==

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//传递name值
<template>
<h2>首页</h2>
<HelloWorld :info="name" />
</template>

<script>
import HelloWorld from '../components/HelloWorld.vue';

export default {
name: 'Home',
components: {
HelloWorld,
},
data () {
return {
name: 'Home',
}
}
}

==子组件==

接收只需定义接收变量的类型即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<template>
<p>{{ info }}</p>
</template>

<script>
export default {
name: 'HelloWorld',
props: {
info: String,
},

setup (props) {
console.log(props.info)
},
}
</script>

context的获取

1
2
3
setup (props, ctx) {
console.log(ctx);
}

setup由于是在组件创建期间完成的,因此其中没有this(当前组件的实例),可以通过传递ctx参数获取当前实例。

3.在setup中使用生命周期函数

可以通过在生命周期钩子前面加上“on”来访问组件的生命周期钩子。

下标包含如何在setup()内部调用生命周期钩子。

options API Hook inside setup
beforeCreate Not needed*
created Not needed*
beforeMount onBeforeMount
mounted onMounted
beforeUpdate onBeforeUpdate
updated onUpdated
beforeUnmount onBeforeUnmount
unmounted onUnmounted
1
2
3
4
5
6
7
8
9
10
11
<script>
import { onMounted } from 'vue';

export default {
setup(){
onMounted(() => {
console.log("渲染1");
})
}
}
</script>
Provide/Inject
  • project()和inject()可以实现嵌套组件之间的数据传递。
  • 这两个函数只能在setup()函数中使用。
  • 父级组件中使用provide()函数向下传递数据。
  • 子级组件中使用inject()获取上层传递过来的数据。
  • 不限层级。

==父组件==

1
2
3
4
5
import { provide } from 'vue';

setup () {
provide("message", "我是大哥大消息")
}

==子组件==

1
2
3
4
5
6
7
import { onMounted, inject } from 'vue';
setup(){
const message = inject("message");
return {
message
};
}
Fragment

Fragment翻译为:“碎片”

  • 不再限于模板中的单个根节点

11.Element-Plus组件库

1.安装组件库

1
2
# NPM
$ npm install element-plus --save

2.全局引用

main.js中引用组件

1
2
3
import ElementPlus from "element-plus"
import 'element-plus/dist/index.full.min.mjs'
import 'element-plus/dist/index.css'

3.按需导入

配置vue.config.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const { defineConfig } = require('@vue/cli-service')
const AutoImport = require('unplugin-auto-import/webpack')
const Components = require('unplugin-vue-components/webpack')
const { ElementPlusResolver } = require('unplugin-vue-components/resolvers')

module.exports = defineConfig({
transpileDependencies: true,
configureWebpack: {
plugins: [
AutoImport({
resolvers: [ElementPlusResolver()],
}),
Components({
resolvers: [ElementPlusResolver()],
}),
],
}
})

4.加载字体图标

1.下载图标
1
2
# NPM
$ npm install @element-plus/icons-vue
2.注册图标
1
2
3
4
5
6
7
8
9
// main.ts

// 如果您正在使用CDN引入,请删除下面一行。
import * as ElementPlusIconsVue from '@element-plus/icons-vue'

const app = createApp(App)
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
app.component(key, component)
}
3.图标实例
1
2
3
<el-icon :size="20" color="green">
<View />
</el-icon>

15.Elasticsearch

1.基本操作

1.创建(更新)索引

1
2
3
4
5
6
PUT test/_doc/1
{
"title": "FIR滤波器的设计方法",
"author": "alleyf",
"content": "FIR滤波器和IIR滤波器都是数字滤波器,我们可以利用MATLAB工具箱对其进行设计。"
}
image-20221220163511348
1
2
3
4
5
6
7
8
9
-index:索引名称
-type:类型
-id:索引id
-version:修改次数(版本号)
-result:操作类型
-shards:分片情况
total:分片总数
successful:成功数
failed:失败数

2.基本查询

==返回值为JSON字符串字典==

1.ID查询
1
GET test/_doc/1
image-20221220164122317
2.全查询
1
GET test/_doc/_search
image-20221220164543339
3.ID删除
1
DELETE test/doc/1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#返回结果
{
"_index" : "test",
"_type" : "doc",
"_id" : "1",
"_version" : 3,
"result" : "deleted",
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 3,
"_primary_term" : 2
}
4.全删除
1
DELETE test/
1
2
3
4
#返回结果
{
"acknowledged" : true
}
5.查询所有存在的索引
1
GET _cat/indices?v

16.Django+Vue


Web_Fast_Development
https://alleyf.github.io/2022/11/aff38a7758c4.html
作者
alleyf
发布于
2022年11月17日
更新于
2024年1月2日
许可协议