ListView类视图
1、在网站开发中,经常会出现需要列出某个表中的一些数据作为列表展示出来.比如文章列表,图书列表等等。在Django中可以使用ListView类视图来帮我们快速实现这种需求
2、即:如果需要在模板中以列表的形式展示一些数据,那么就可以使用ListView类视图来快速实现
3、ListView类视图跟前面介绍的View类视图和TemplateView类视图一样,都是为了方便我们快速实现某些特定功能的类视图
⑴这些类视图jango已经封装好了的,我们只需要继承对应的类以及重写某些属性和方法就可以了
例1:
⑴编辑视图
⑵编辑模板
⑶查看数据库数据
⑷访问第一页
⑸访问第二页
注:
1、上面例子中我们只是很简单的写了一个类视图,并继承于ListView类视图,就很容易的实现了一个列表显示页面
⑴在从数据库获取数据时,我们并没有使用SQL语句进行查询,只是提供了一个模型名,但成功的从对应表中查询出了数据
⑵在数据显示方面,我们只是定义了一个URL,但是可以通过查询字符串的方式来访问第二页的数据
⑶可以看出:有很多东西都是Django封装好了的,我们只需要按照我们的需要来传入对应的属性(方法)值就可以了
⑷模板在ListView类视图中是没有封装的,这个是完全需要我们自己来写的:相当于就是Django已经给你封装好了数据分页的视图了,我们要做的就是定义好传递给模板的参数以及模板
2、上面例子只是一个很简单的ListView类视图,主要是先熟悉下这个类视图里面有哪些东西
3、这个例子中:翻页功能我们是通过手动在地址栏中输入URL实现的。实际中应该是有个翻页按钮之类的,通过这个翻页按钮来向后端传递这个查询字符串参数值的
4、这个例子中:数据库中一共有四条数据,每页显示2条,那么总共有2页。我们如果让page=3的话,就会找不到页面。如果我们在网址后面没有传递page参数,默认返回的就是第一页。
ListView类视图属性、方法
属性、方法名 | 描述 |
model | 重写model类属性,指定这个列表是给哪个模型的 |
template_name | 指定这个列表的模板 |
paginate_by | 指定这个列表一页中展示多少条数据 |
context_object_name | 指定这个列表模型在模板中的参数名称(传递到模板的参数名:键名) |
ordering | 指定这个列表的排序方式 |
page_kwarg | 获取第几页的数据的参数名称。默认是page |
get_context_data | 获取上下文的数据 |
get_queryset | 根据需要来查询数据,默认是全部数据(all方法) |
page_kwarg属性
1、page_kwarg属性值用来来修改查询字符串参数的参数名
2、这些属性可以理解为Python中的类属性:整个类公用的属性
例2:修改URL中页数参数名
⑴编辑视图
⑵访问第一页
⑶访问第二页
注:
1、可以通过"page_kwarg"属性值来修改查询字符串参数的参数名
2、URL中的查询字符串参数是不会影响的URL匹配的:查询字符串参数只是用于视图函数获取参数的(根据参数来返回对应的内容)
⑴即使访问的URL中的查询字符串参数的参数名错误了,还是可以正常访问的,只是说访问的内容可能不是正确的
⑵比如,这个例子中访问第二页时,正确的URL是:http://127.0.0.1:8000/zh/index/?p=2,但是我们实际访问的是http://127.0.0.1:8000/zh/index/?page=2
⑶由于http://127.0.0.1:8000/zh/index/是正确的,可以正常访问(访问的额第一页),由于查询字符串参数名错了,视图函数中不能获取到对应的值。因此不管其值时多少,实际上访问的都是第一页
get_context_data方法
1、get_context_data方法用来:获取上下文的数据,并且可以添加自己的参数
2、前面的例子中我们直接是将从数据库中查询出来的数据,传递给了模板,这些数据我们也不知道具体是什么样子的
⑴因此可以使用get_context_data方法来打印这些数据(打印从数据库中查询到的数据,以及其他一些信息)
⑵并且也可以使用该方法来额外添加某些参数值
例3:获取上下文
⑴数据源
⑵编辑视图
注:
可以看到整个上下文数据是一个字典
⑴模型中的数据:其键名为"context_object_name"属性指定的值"books",其值就是查询数据组成的QuerySet对象
①因此要获取查询数据,就可以使用其键名(books)来获取
⑵自己添加的数据:直接以键值对的形式存在
①因此要获取添加的数据,就可以使用其键名来获取
⑶另外整个字典中还有些其他的键值对,比如Paginator类还是Page类(都是以键值对的形式存在的),这些后面介绍
⑶编辑模板
⑷编辑URL
⑸访问:第一页
⑹访问:第N页
注:
1、输出结果里面包含了很多东西,有我们常用的paginator类、page_obj类和我们自定义的一些参数等。paginator类、page_obj类下面将会进行讲解
2、可以看到,其实上面有很多代码是我们自己没有写的,都是ListView视图类封装好了,我们只需要设置好对应属性的值和方法的值以及模板就好了。比如数据是如何分页的,如何去获取第N页的数据,这些都不是我们完成的
get_queryset方法
get_queryset:如果你提取数据的时候,并不是要把所有数据都返回,那么你可以重写这个方法。将一些不需要展示的数据给过滤掉
例4:
⑴编辑视图
⑵访问
注:
需要记住:这些Django内置的类视图只是帮你封装好了如何实现一些功能(视图),至于向前端传递哪些数据、数据如何在前端进行展示都是需要我们自己去定义的
Paginator和Page类
Django提供了数据分页的类,这些类被定义在django/core/paginator.py中
⑴对象Paginator用于对列进行一页n条数据的分页运算
⑵对象Page用于表示第m页的数据
paginator类对象的属性
属性名 | 说明 |
conunt | 总共多少条数据 |
num_pages | 返回分页之后的总页数 |
page_range | 返回分页后页码的列表。比如有三页,那么就是range(1,4) |
Paginator类对象的方法
方法名 | 说明 |
page(self, number) | 返回第number页的Page类实例对象 |
Page类对象的属性
属性名 | 说明 |
number | 返回当前页的页码 |
start_index | 当前这一页的第一条数据的索引值 |
end_index | 当前这一页的最后一条数据的索引值 |
object_list | 返回包含当前页的数据的查询集 |
paginator | 返回对应的Paginator类对象 |
Page类对象的方法
方法名 | 说明 |
has_previous | 判断当前页是否有上一页 |
has_next | 判断当前页是否有下一页 |
previous_page_number | 返回前一页的页码 |
next_page_number | 返回下一页的页码 |
注:
1、前面在介绍ListView类视图时,打印过向前端传递过去的上下文content。ListView类视图的content里面就包含了Paginator和Page类
2、因此,我们只需要使用Paginator和Page类中的类属性(方法)就可以实现更加完美是分页功能了
3、前面例子中,在请求第N页的数据时,采用的是直接手动在URL中输入"?pages=2"这样的参数。这在实际中肯定是不行的,一般都是通过前端点击第N页按钮后,前端自动获取当前页码然后自动添加到URL中并传递给服务器
例5:打印content
⑴查看ListView类视图返回
⑵目的
Paginator类属性
1、ListView类视图返回的是一个字典,因此可以直接使用字典方法来获取其中某个键的值:paginator类
2、获取到paginator类后,就可以使用其属性来获取对应的属性值了
3、Paginator类主要返回的是数据个数、分页条数的一些数据
例6:
⑴编辑视图
⑵数据库数据
Page类属性
1、ListView类视图返回的是一个字典,因此可以直接使用字典方法来获取其中某个键的值:Page类
2、获取到paginator类后,就可以使用其属性来获取对应的属性值了
3、Page类主要用于对当前所处页的一些信息
例7:
⑴编辑视图
⑵编辑模板
⑶访问:第一页
例7_1:
⑴编辑视图
注:
1、不管是Paginator类还是Page类:它们的属性值都是在重写后的get_context_data()中获取的
2、当然也可以在模板中直接获取:它们是跟着content一起传递给模板的,只是说其值类型是一个class(类)
⑴如果上下文中键的值是一个类对象的话,就需要使用:{{键名.属性名}}的方式来访问了
分页示例
这里介绍一个比较粗糙的分页示例
例8:
⑴编辑视图
⑵编辑模板
⑶编辑URL
⑷访问
拓展
对数据进行分页操作
1、对数据进行分页操作的方法有很多,自己感觉还是前后端分离比较好
⑴前端请求时,向服务器传递当前请求的第n页与每页显示多少条数据,后端只需要将当前请求的那几条数据传递给前端就好了
2、至于后端如何根据前端传递来的"第n页与每页显示多少条数据"参数,去查询对应的数据的方法就有几种方法了
⑴使用LIMIT(Mysql中):通过在查询SQL语句中加入LIMIT关键字来达到返回部分数据的效果:这样直接查询出来的数据就是需要返回给前端的数据
⑵使用分片:使用SQL语句查询出全部符合条件的数据,这些数据是一个嵌套元组(列表),因此可以根据传入的参数来分片出对应的数据
⑶在对数据进行LIMIT或分片操作时,还可以使用ORDER BY来对数据进行排序(排序后使用LIMIT或分片)
例1:分片
import pymysql
db_conn = pymysql.connect(user="root",password="123456",host="localhost",database="zhouh",port=3306)
db_cursor = db_conn.cursor()
sql = """SELECT id,title,price,author FROM polls_article ORDER BY title"""
"""分页效果是没法在SQL语句中完成的,只能在代码中实现"""
def SelectResult(pageSize, currentPage):
db_cursor.execute(sql)
#先查询出所有数据
selectResults = db_cursor.fetchall()
total = len(selectResults)
print("数据个数为:", len(selectResults))
# 计算查询数据个数最多显示多少页:数据总条数除以每页显示条数
PageInfo = divmod(total, pageSize)
# 值小于0,表示total>pageSize,一页就能显示完,因此总页数为1
if PageInfo[0] == 0:
maxPage = 1
else:
# 有值且余数等于0,表示刚好显示完全,总页数为商
if PageInfo[1] == 0:
maxPage = PageInfo[0]
# 有值且有余数(不为0),表示多出来了n条(n<5),总页数为商+1
else:
maxPage = PageInfo[0] + 1
# 判断当前请求页是否存在:不存在
if currentPage > maxPage or currentPage <= 0:
data = {
"total": total,
"pageSize": pageSize,
"currentPage": currentPage,
"data": []}
return data
else:
# 查询结果个数为0时
if total == 0:
data = {
"total": total,
"pageSize": pageSize,
"currentPage": currentPage,
"data": selectResults}
return data
# 查询结果个数大于0小于pageSize时:一次性全部返回
elif 0 < total < pageSize:
data = {
"total": total,
"pageSize": pageSize,
"currentPage": currentPage,
"data": selectResults}
return data
# 查询结果个数大于pageSize时:返回当前请求页的数据
else:
# 根据分片来返回当前页的数据
start = (currentPage - 1) * pageSize
end = currentPage * pageSize
data = {
"total": total,
"pageSize": pageSize,
"currentPage": currentPage,
"data": selectResults[start:end]}
return data
datas = SelectResult(5, 1)
print(datas)
for data in datas["data"]:
print(data)
"""
#这段代码中最重要的就是:如何确定当前请求的是哪些数据(start变量值和end变量值),另外还有些判断,比如确定当前页面
数据个数为: 6
{'currentPage': 1, 'total': 6, 'data': ((8, 'ds', 123.0, '32'), (7, 'wed', 123.0, '32'), (2, '三国演义', 154.0, '罗贯中'), (4, '水浒传', 140.0, '施耐庵'), (3, '红楼梦', 141.0, '曹雪芹')), 'pageSize': 5}
(8, 'ds', 123.0, '32')
(7, 'wed', 123.0, '32')
(2, '三国演义', 154.0, '罗贯中')
(4, '水浒传', 140.0, '施耐庵')
(3, '红楼梦', 141.0, '曹雪芹')
"""
例1_1:LMIT
import pymysql
db_conn = pymysql.connect(user="root",password="123456",host="localhost",database="zhouh",port=3306)
db_cursor = db_conn.cursor()
def SelectResult(pageSize, currentPage):
start = (currentPage - 1) * pageSize
end = currentPage * pageSize
sql = """SELECT id,title,price,author FROM polls_article ORDER BY title LIMIT %s,%s"""%(start,end)
db_cursor.execute(sql)
selectResults = db_cursor.fetchall()
return selectResults
selectResults = SelectResult(5,1)
print(selectResults)
"""
实例LIMIT来查询数据的话,感觉就没法计算数据总条数和判断当前请求页实际是否存在了
((8, 'ds', 123.0, '32'), (7, 'wed', 123.0, '32'), (2, '三国演义', 154.0, '罗贯中'), (4, '水浒传', 140.0, '施耐庵'), (3, '红楼梦', 141.0, '曹雪芹'))
"""