相信的心就是你的魔法

Django基础与投票应用

Django简介

Python下有许多款不同的 Web 框架。Django是重量级选手中最有代表性的一位。许多成功的网站和APP都基于Django。

  • Django是一个开放源代码的Web应用框架,由Python写成。

  • Django遵守BSD版权,初次发布于2005年7月, 并于2008年9月发布了第一个正式版本1.0 。

  • Django采用了MVC的软件设计模式,即模型M,视图V和控制器C。

(转自菜鸟教程 https://www.runoob.com/django/django-tutorial.html

创建并运行Django项目

创建django项目的方法很多,这里主要介绍三种方法:

方法一

  • 首先保证已经拥有python开发环境,之后在终端中使用pip install的指令安装django依赖项

  • 在安装完django依赖项之后,我们可以使用django admin的工具用来创建我们的django项目,使用指令django-admin startproject 项目名,这个时候在使用命令的目录下就会生成一个以项目名命名的项目文件夹,其中包含了项目的配置文件,url的映射文件,还有django的管理工具manage.py。

  • 之后我们可以使用pycharm打开创建好的项目文件夹,然后开始配置项目的虚拟环境。

    • 配置虚拟环境有两种方法,一种是在pycharm中利用File —> setting —> Project —> Project Interpreter —> Add 的方法创建虚拟环境。

    • 也可以利用pycharm中的终端功能,直接在终端里输入python -m venv(模块名) venv(虚拟文件文件夹的名字) 或者利用virtualenv这一个工具,在终端中输入virtualenv --python==/usr/bin/python3(python的安装路径) venv(虚拟文件夹的名字)

  • 激活虚拟环境:苹果Linux系统下使用source venv/bin/activateWindows系统下使用venv/Scripts/activate的指令激活虚拟环境

  • 在虚拟环境中安装django依赖项,在pycharm终端中输入pip install django==2.1.15(可以自己指定想要安装的版本)

  • 运行项目,这里依然有两种方法,第一种方法是直接在pycharm的终端中输入python manage.py runserver另一种方式就是创建一个快捷的启动按钮,Add Configuration —> + —> Python —> Script Path(选中django项目文件中的manage.py) —> Parameters(runserver)

方法二

  • 用pycharm创建一个普通的python项目
  • 安装djiango所需的依赖项,在pycharm终端中输入pip install django==2.1.14
  • 把Python项目变成django项目
    django-admin startproject 创建的Python项目名 .(注意这个.不要漏了,这个.表示在当前目录下创建django项目)
  • 运行项目的步骤同方法一

方法三

  • 克隆项目到本地:使用pycharm的”get from version control” —> 输入保存项目的路径和克隆的远程仓库地址eg:”[email protected]:xxxx/djangoP.git”

  • 克隆的项目通常不包含虚拟环境,因此需要激活虚拟环境:Linux/MacOS系统下使用source venv/bin/activateWindows系统下使用venv/Scripts/activate的指令激活虚拟环境

  • 重建依赖项pip install -r requirements.txt

  • 运行项目:方法同上

当我们把django项目创建好并运行之后,通过访问https://127.0.0.1:8000/ ,我们就能够看到django项目的默认欢迎页面啦

django默认欢迎页面

django投票项目

django项目创建

我们创建一个名为djangoP的项目(略)

设置配置文件

数据库设置

django项目的配置文件中,默认使用的是sqlite数据库,而开发过程中我们更常使用mySQL等关系型数据库,这里以mySQL数据库的配置为例来讲解该项目

  • 在服务器上启动mySQL:systemctl start mysqld,启动之后可以利用netstat -ntlp检查mySQL是否成功启动

  • 使用mySQL客户端工具(或者可视化的程序,如navicat等)连接mySQL:mysql -u root (-h ip地址) -p(注意,连本机不需要-h,而连接非本机则需要输入服务器的ip地址),回车之后输入登录的口令密码即可成功连接。

  • show databases查看当前服务器存在的数据库,mySQL中主要有三类的操作:

    • DDL(Data Definition Languages)数据定义语句 —> create/drop/alter ;
    • DML(Data Manipulation Language)数据操纵语句,用于数据库记录的增删改查操作 —> insert/delete/update/select(select有时也被单独成为DQL类操作);
    • DCL(Data Control Language)数据库控制语言,主要用于对数据库的操纵权限的分配操作 —> grant/revoke
  • 这里我们为本次的投票项目新建一个数据库create database djangopolls default charset utf8;(注意,为防止存入中文时出现编码错误,这里要指定编码方式),use djangopolls使用当前数据库,show tables查看当前数据库中的表

  • 注意:在项目过程中,我们往往不会直接使用root超级管理员账号,而是新建一个用户并且授予其项目实施过程中所需要的权限,这样的做法更加科学和安全,因此,这里我们需要创建一个新的用户。create user 'hanlin'@'%' identified by '123456(该用户的登录口令);'“@”之后的字段表示只允许该用户从某一个特定的主机连接该服务器。“%”表示该用户可以从任意主机连接服务器。grant all privileges on djangopolls.* to 'hanlin'@'%';赋予“hanlin”这个用户在“djangopolls”这个数据库里对该数据库的所有权限。

  • 当数据库和用户创建完毕之后,我们可以修改django项目配置文件中的“DATABASE”

1
2
3
4
5
6
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
1
2
3
4
5
6
7
8
9
10
11
12
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'djangopolls',
'HOST': '47.96,21,76',
'PORT': 3306,
'USER': 'hanlin',
'PASSWORD': '123456',
'CHARSET': 'utf8',
'TIME_ZONE': 'Asia/Chongqing',
}
}
创建应用
  • 数据库配置完成后,我们可以开始创建我们的投票应用了。在pycharm的终端中输入python manage.py startapp polls或者django-admin startapp polls,创建好之后我们会发现项目下多了一个“polls”的文件夹,其中有很多py文件。

    • 这里我们引入一些新的知识点,我们在开发项目中常常会使用一种开发模式,特别是功能比较复杂的项目,更需要对功能,对结构进行拆分,其中有一种“MVC架构模式”非常泛用。

      Model - View - Controller

      模型 - 视图 - 控制器

      数据 - 数据的显示 - 控制器(粘合数据和数据的显示)

      数据和数据的显示要分离(数据和显示的解耦合),我们写程序的时候一定要遵循“高内聚,低耦合”的原则。我们在写前端界面时也用到了数据和数据显示相分离的结构,比如我们在标签中写的是数据,而数据的显示则是写在样式表中

      在django中,依然遵循“MVC架构模式”,但是命名方式稍有区别

      Model - Template - View

      模型 - 模板 - 视图

      数据 - 数据的显示 - django中的视图扮演了控制器的角色

    • 我们现在再来看我们创建的应用“polls”,其中的“models”文件就是用来存放模型的,而“views”则是存放视图的文件,此时我们还需要创建一个“templates”的文件夹来存放模板。我们在项目“djangoP”目录下创建“templates”文件夹,创建好文件夹之后我们还需要去配置文件中配置模板的路径,在配置文件“setting.py”中找到“TEMPLATES”,其中的“DIRS”就是配置“templates”路径的地方。注意:此处的路径要写绝对路径,由于“setting.py中声明了BASE_DIR”即项目根路径,而“templates”文件夹就是根路径下,此处我们可以直接拼接:os.path.join(BASE_DIR, 'templates')到此位置模板也配置完成了,“MTV”架构全部完成!

templates路径配置

配置视图文件和urls统一资源定位符管理文件实现简单的访问
  • 控制器的配置,前面我们说过“views.py”在django中扮演了控制器的角色,那么它主要承担了怎样的工作呢?

    • 接收用户的请求
    • 操作模型
    • 产生响应(渲染页面)
  • 视图函数:

    • 在views.py中声明函数
    • 在urls.py中配置返回链接
1
2
3
# 当用户发起请求,系统给一个回应,这里要从django提供的库django.http中导入HttpResponse模块
def index(request:HttpRequest):
return HttpResponse('<h1>Hello, Django!</h1>')
1
2
3
4
urlpatterns = [
path('admin/', admin.site.urls),
path('', index), # 当访问时不添加任何资源路径,返回index
]

完成以上步骤之后,我们再次访问https://127.0.0.1:8000/ 会发现,django默认界面不见了,取而代之的是我们写好的“Hello,Django!”

Django ORM对象关系映射框架
  • 向数据库存数据的时候:对象变关系
  • 从数据库读数据的时候:关系变对象

python中为我们提供了对象模型,而mySQL中采用的却是关系模型,这两种模型是不匹配的。

比如说我们在python中创建了一个类Fruit,然后我们创建了一个Fruit的对象fruit;按照面向对象的思路。我们想删除这个对象时,我们可以使用类方法,比如说fruit.delete()就能删除这个对象,fruit.save()就能添加这个对象。

而在数据库中,我们却不能采用这种方法,我们需要先创建一个游标对象cursor,然后用cursor.execute('insert into tb_fruit values (%s, %s)')来添加数据。

如果没有ORM框架,我们需要在python中利用拼接字符串的方法来写sql的语句,这就非常麻烦了。

而django中的ORM就能帮助我们解决这些矛盾,当我们从sql数据库中拿到数据的时候,ORM框架就能把自动帮我们把这些数据转换成python对象。这样虽然方便,但是会以牺牲性能为代价。

教师投票应用

  • 在models.py中建立模型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Subject(models.Model):
"""学科模型类"""

no = models.AutoField(primary_key=True, verbose_name='编号')
name = models.CharField(max_length=20, verbose_name='名称')
intro = models.CharField(max_length=1000, verbose_name='介绍')
is_hot = models.BooleanField(default=False, verbose_name='是否热门')
memo = models.CharField(max_length=256, null=True)

"""这里我们需要在学科类中再声明一个Meta类来定义该学科类的一些属性"""
class Meta:
# 把该学科类绑定到sql数据库的一张表“tb_subject”上
db_table = 'tb_subject'
verbose_name = '学科'
verbose_name_plural = '学科'
  • 在setting.py中的“INSTALLED_APPS”中添加我们的投票应用“polls”

setting.py中的“INSTALLED_APPS”

  • 在pycharm的终端中执行牵引操作,把我们的模型变成表添加到sql数据库中。生成迁移python manage.py makemigrations polls执行该操作之后,会在polls目录下生成一个migration的迁移文件;执行迁移python manage.py migrate,把刚才生成的迁移直接变成数据库中的表

  • 在执行完迁移之后我们访问我们的数据库,查看所有的表show tables,我们可以看见我们刚刚创建的那张表“tb_subject”,然后我们可以向这张表中添加一些字段

1
2
3
4
insert into tb_subject (name, intro) values 
('Python+人工智能', 'Python是一种跨平台的计算机程序设计语言。是一种面向对象的动态类型语言,最初被设计用于编写自动化脚本(shell),随着版本的不断更新和语言新功能的添加,越来越多被用于独立的、大型项目的开发。'),
('JavaEE+分布式', 'Java是一门面向对象编程语言,不仅吸收了C++语言的各种优点,还摒弃了C++里难以理解的多继承、指针等概念,因此Java语言具有功能强大和简单易用两个特征。Java语言作为静态面向对象编程语言的代表,极好地实现了面向对象理论,允许程序员以优雅的思维方式进行复杂的编程。'),
('HTML5+跨平台', 'HTML5是构建Web内容的一种语言描述方式。HTML5是互联网的下一代标准,是构建以及呈现互联网内容的一种语言方式.被认为是互联网的核心技术之一。HTML产生于1990年,1997年HTML4成为互联网标准,并广泛应用于互联网应用的开发。');
  • 创建一个首页去获取数据库中的数据并展示出来

接下来我们回到views.py文件中,重写index视图函数

1
2
3
4
5
6
7
8
9
10
def index(request):
"""首页"""
"""注意这里要导入Subject"""
"""Subject继承了Model类,而Model类中给模型绑定了一个objects的属性,而这个objects就是模型的管理器对象,其中有一个all的方法,通过该方法可以拿到模型中的所有对象,并返回一个叫queryset的查询集对象"""
queryset = Subject.objects.all()
context = {
'subjects': queryset
}

return render(request, 'index.html', context)

渲染页面:在templates目录下创建index.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>首页</title>
</head>
<body>
<h2>所有学科</h2>
<hr>
{% for subject in subjects %}
<!-- Django模板页,可以使用Django模板语言模板指令来生成动态内容 -->
<div class="subject">
<p>{{ subject.name }}</p>
<p>{{ subject.intro }}</p>
</div>
{% endfor %}
</body>
</html>
django自带的管理员平台

访问https://127.0.0.1:8000/admin/ 我们会发现 django已经为我们内置了一个管理中心,通过该管理中心,我们能很方便地管理模型中的所有的对象,但是这个中心需要登录才能使用

django自带的管理员平台

  • 打开我们的项目的pycharm终端,输入python manage.py createsuperuser回车之后会让你创建一组用户名和密码口令(如果不输入就默认是登录本机时使用的账号和密码口令)

  • 注册自己的模型:在应用目录“polls”中,我们能找到一个叫“admin.py”的文件,在这个文件中我们可以注册我们的模型

1
admin.site.register(Subject)

Subject模型

  • verbose_name/verbose_name_plural:可以在创建模型的时候传入参数指定字段的显示
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Subject(models.Model):
"""学科模型类"""

no = models.AutoField(primary_key=True, verbose_name='编号')
name = models.CharField(max_length=20, verbose_name='名称')
intro = models.CharField(max_length=1000, verbose_name='介绍')
is_hot = models.BooleanField(default=False, verbose_name='是否热门')
memo = models.CharField(max_length=256, null=True)

def __str__(self):
return self.name

class Meta:
db_table = 'tb_subject'
verbose_name = '学科'
# 复数的显示
verbose_name_plural = '学科'
  • 同时我们还可以在注册模型的时候定制模型的显示: 我们可以在“admin.py”中申明一个模型管理的类“SubjectAdmin”,在“admin”中的“ModelAdmin”这一个类中,提供了“list_display”的方法,可以定制模型的显示
1
2
3
4
5
6
7
8
9
10
11
12
class SubjectAdmin(admin.ModelAdmin):
# 设定显示内容
list_display = ('no', 'name', 'intro')
# 设定点击跳转的字段,不设定时默认为主键可点击跳转查看
list_display_links = ('name',)
# 设定可用于搜索的字段
search_fields = ('name',)
设定排序规则
ordering = ('no',)


admin.site.register(Subject, SubjectAdmin)
静态资源路径的设置

为方便实验,我们直接在项目的根目录下,与模板(templates)平级,创建“static”文件夹,用于存放项目所需的静态资源。我们的静态资源一般分为三类:images(图片文件)、css(样式表)、js文件,我们可以直接在“static”文件目录下创建这三个文件夹。

创建静态资源路径

配置好静态资源目录之后,我们还需要在配置文件中对调用静态资源的路径进行配置,在“setting.py”中,我们需要进行如下设置

1
2
3
4
# 指定静态资源所在的文件的路径
STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static'), ]
# 指定静态资源在调用时路径名前缀(注意,这里的/static/和文件夹“static”无关,可以随便命名)
STATIC_URL = '/static/'

这个时候我们就可以往我们的页面中插入图片了,这里我们给热门学科后面加上一把小火苗

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>
</head>
<body>
<h2>所有学科</h2>
<hr>
{% for subject in subjects %}
<!-- Django模板页,可以使用Django模板语言模板指令来生成动态内容 -->
<div class="subject">
<p>{{ subject.name }}
{% if subject.is_hot %}
<img src="/static/images/hotfire.png">
{% endif %}
</p>
<p>{{ subject.intro }}</p>
</div>
{% endfor %}
</body>
</html>

给热门学科添加小火苗

创建老师的模型

我们要做的是一个给老师投票的应用,现在我们的学科模型已经建立好了,接下来我们要建立老师的模型。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Teacher(models.Model):
"""老师(模型类)"""
no = models.AutoField(primary_key=True, verbose_name='工号')
name = models.CharField(max_length=20, verbose_name='姓名')
gender = models.BooleanField(default=True, verbose_name='性别')
birth = models.DateField(verbose_name='出生日期')
photo = models.ImageField(upload_to='images', default='', max_length=512, verbose_name='头像')
intro = models.CharField(default='', max_length=1000, verbose_name='介绍')
good_count = models.PositiveIntegerField(default=0, verbose_name='好评数')
bad_count = models.IntegerField(default=0, verbose_name='差评数')

"""老师和学科之间是多对一的关系,一个学科中可以有多个老师,而一个老师通常只属于一个学科,这个时候我们就需要用到外键约束了,外键约束一般添加到多的一方"""
subject = models.ForeignKey(to=Subject, on_delete=models.PROTECT, db_column='sno', verbose_name='所属学科')

class Meta:
db_table = 'tb_teacher'
verbose_name = '老师'
verbose_name_plural = '老师'

模型建立之后要再次进行模型的迁移:python manage.py makemigrations pollspython manage.py migrate,之后我们新建的模型就能生效啦。然后我们在“admin.py”中注册老师的模型

1
2
3
4
5
6
7
8
class TeacherAdmin(admin.ModelAdmin):
list_display = ('no', 'name', 'gender', 'birth', 'intro', 'good_count', 'bad_count',)
list_display_links = ('no', 'name',)
search_fields = ('name', )
ordering = ('no', )


admin.site.register(Teacher, TeacherAdmin)
对主页的学科映射url使我们在点击学科的时候能跳转到老师的页面

我们先回到主页的模板文件“index.html”中,把学科名的<p>标签换成超链接<a>标签,我们可以设计一个这样的标签

1
<a href="/teachers/?sno={{subject.no}}">{{ subject.name }}</a>

我们要在url后面加参数需要用?来表示,如<a href="/teachers/?a=b&c=d</a>,这表示我们要引入两组参数,a=b,c=d。这里因为我们点击该学科的名称后想要看到该学科对应的所有的老师的信息,而通过我们建立的老师和学科的模型我们可以知道老师和学科靠外键“学科编号”产生关联,因此这里我们最好引入学科编号作为参数。

设置好之后,我们回到主页面,把我们的鼠标悬停在学科名上,然后查看浏览器窗口右下角我们会发现

悬停在学科名上

设置显示老师的视图函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def show_teachers(request):
"""显示指定学科的老师"""
try:
"""我们在点击学科的时候通过GET请求拿到“sno”这个参数"""
sno = request.GET['sno']
"""拿到学科编号之后,我们就可以在学科模型中查询我们拿到的编号所对应的学科""
subject = Subject.objects.get(no=sno)
"""拿到学科编号之后,我们就可以在老师模型中查询我们拿到的编号所对应的老师,这里注意,老师模型中并没有学科编号,只有学科字段,学科编号是学科中的信息,因此我们通过subject__no的方式拿到学科编号"""
queryset = Teacher.objects.filter(subject__no=sno)
context = {
'subject': subject,
'teachers': queryset
}
"""返回渲染一个teachers.html的页面"""
return render(request, 'teachers.html', context)
except (KeyError, ValueError, Subject.DoseNotExist):
return redirect('/')
创建老师信息的模板页

由老师的视图函数可以知道,函数执行完最终会渲染一个teachers.html的页面,因此,我们需要创建这个页面,在“templates”文件夹下新建“teachers.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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>首页</title>
<style>
.photo{
margin-top:30px;
width:140px;
height:140px;
float:left;
border-radius:70px 70px 70px 70px;
overflow:hidden
}
.content{
margin:60px;
width:580px;
float:left;

}
.teacher{
clear:both;
}

</style>
</head>
<body>
<h2>{{ subject.name }}学科老师的信息</h2>
<hr>
{% for teacher in teachers %}
<div class="teacher">
<div class="photo">
<img src="{{ teacher.photo.url }}" width="140px">
</div>
<!-- Django模板页,可以使用Django模板语言模板指令来生成动态内容 -->
<div class="content">
<p>
{{ teacher.name }}&nbsp;&nbsp;
{{teacher.gender | yesno:"男, 女"}}&nbsp;&nbsp;
{{teacher.birth}}
</p>
<p>{{ teacher.intro }}</p>
<p class="comment">
<a href="/good/?tno={{ teacher.no }}">好评</a>
<span>{{ teacher.good_count}}</span>

<a href="/bad/?tno={{ teacher.no }}">差评</a>
<span>{{ teacher.bad_count}}</span>
</p>
</div>
</div>
{% endfor %}

</body>
</html>

最后我们还需要设置url路径,在“urls.py”文件中的“urlpatterns”中添加如下代码:

1
path('teachers/', show_teachers),

上述代码表示访问’teachers/‘时会调用“show_teachers”函数。之后我们访问我们的首页,点击学科之后就能看见老师的信息了。

投票的实现

在前面我们创建的老师的模板页中,我们为每个老师添加了好评和差评的<a>标签,以及可以显示票数的<span>标签,依照之前的步骤,我们需要创建好评与差评的视图函数,然后在“urls.py”文件中映射路径。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def praise_or_criticize(request):

tno = request.GET.get('tno', '0')
try:
teacher = Teacher.objects.get(no=tno)
"""request对象中包含有path属性,可以拿到请求的路径"""
if request.path.startswith('/good'):
teacher.good_count += 1
else:
teacher.bad_count += 1
teacher.save()
except (ValueError, Teacher.DoesNotExist):
pass
return redirect(f'/teachers/?sno={sno}')

写完了视图函数之后别忘了在“urls.py”文件中设置映射路径,在“urlpatterns”中添加

1
2
path('good/', praise_or_criticize),
path('bad/', praise_or_criticize),

好了,现在我们看看,在首页点击学科进入老师界面之后是不是就可以对老师投票了呢?

功能的完善(提高)

ajax异步请求实现界面的局部刷新

虽然我们已经简单的实现了给老师投票的功能,但是我们也发现了,当我们点击好评或差评的按钮时,不仅数字会发生变化,整个界面也会跟着刷新。这是完全没有必要的,因为页面中的其他数据并没有发生变化,不需要刷新,所以说这里我们可以通过引入ajax,实现页面的局部刷新,在进行投票的时候,只对票数进行刷新,页面的其他部分不发生变化。

这里我们需要修改视图函数“praise_or_criticize”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def praise_or_criticize(request):

tno = request.GET.get('tno', '0')
try:
teacher = Teacher.objects.get(no=tno)
"""request对象中包含有path属性,可以拿到请求的路径"""
if request.path.startswith('/good'):
teacher.good_count += 1
else:
teacher.bad_count += 1
teacher.save()
"""这里我们创建一个data字典用来保存函数执行的结果"""
data = {'code': 10000, 'message': '操作成功'}
except (ValueError, Teacher.DoesNotExist):
data = {'code': 10001, 'message': '操作失败'}
"""把函数执行结果转化为json数据然后作为返回值,之前我们都是直接返回渲染界面,现在直接在模板中通过ajax来做异步请求"""
return JsonResponse(data)

改完了视图函数之后我们在“teachers.html”模板中添加如下代码,这里需要用到Jquery

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
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
<script>
// $()函数中的箭头函数是页面加载完成之后要执行的回调函数
$(() => {
let flag = true
// 通过$(选择器)获取页面元素绑定点击事件
// on方法的第一个参数是事件名 第二个参数是事件回调函数
// 事件回调函数的参数evt是代表事件的对象
$('.comment>a').on('click', (evt) => {
// 阻止事件默认行为(避免直接刷新页面)
evt.preventDefault()
// 通过事件对象获取事件源并由$函数转成jQuery对象
if(flag){
// 实现函数节流
flag = false
setTimeout(() => { flag = true }, 2000)
// 这里的evt.target就相当于this,即事件源,但是直接取evt.target拿到的是原生的js对象,这里我们需要把它放在$()中转化为一个jQuery对象
let anchor = $(evt.target)
// 通过jQuery对象的getJSON方法发起Ajax请求
// getJSON方法:发出get请求拿回json数据
// attr()是jQuery中的一个对象方法,可以拿到对象的属性
// 第一个参数是请求事件源对应的URL
// 第二个参数是请求完成之后要执行的回调函数
$.getJSON(anchor.attr('href'), (json) => {
if (json.code == 10000) { // 投票成功
// 获取与a标签相邻的span标签
let span = anchor.next()
// 将span标签的值加1再写回span标签
span.text(parseInt(span.text()) + 1)

} else{
alert(json.message)
if (json.code == 10002){
location.href = '/login/?backurl='+ btoa('/teachers/?sno={{ subject.no }}')}
}
})
}else{
alert('操作太频繁')
}
})
})
</script>

注意:以上代码除了实现异步请求,还完成了数据节流的功能,让用户每隔两秒才能点击一次

登陆功能的实现
------ 本文结束------