python 全栈开发,Day79(Django的用户认证组件,分页器)
一、Django的用戶認證組件
用戶認證
auth模塊
在進行用戶登陸驗證的時候,如果是自己寫代碼,就必須要先查詢數據庫,看用戶輸入的用戶名是否存在于數據庫中;
如果用戶存在于數據庫中,然后再驗證用戶輸入的密碼,這樣一來就要自己編寫大量的代碼。
事實上,Django已經提供了內置的用戶認證功能。
在使用"python manage.py makemigrationss"和"python manage.py migrate"遷移完成數據庫之后
根據配置文件settings.py中的數據庫段生成的數據表中已經包含了6張進行認證的數據表,分別是
- auth_user
- auth_group
- auth_group_permissions
- auth_permission
- auth_user_groups
- auth_user_user_permissions
進行用戶認證的數據表為auth_user
要使用Django自帶的認證功能,首先要導入auth模塊
from django.contrib import auth #導入auth模塊django.contrib.auth中提供了許多方法,這里主要介紹其中的三個:
1.1 、authenticate()?
提供了用戶認證,即驗證用戶名以及密碼是否正確,一般需要username? password兩個關鍵字參數
如果認證信息有效,會返回一個? User? 對象。authenticate()會在User 對象上設置一個屬性標識那種認證后端認證了該用戶,且該信息在后面的登錄過程中是需要的。當我們試圖登陸一個從數據庫中直接取出來不經過authenticate()的User對象會報錯的!!
user = authenticate(username='someone',password='somepassword')舉例:
使用Pycharm新建項目authDemo
執行2個命令,生成django需要的表
python manage.py makemigrations python manage.py migrate我們只需要用到auth_user表,就可以了!
打開auth_user表,默認是空的。其中2個字段,username和password是必須要有的!
注意:添加用戶,不能直接插入記錄,必須使用命令行
創建超級用戶
python manage.py createsuperuser效果如下:
查看auth_user表,發現多了一條記錄
注意:密碼是加密的,不能直接查表驗證。必須使用authenticate() 進行驗證!
?
修改urls.py,增加路徑
from app01 import views urlpatterns = [path('admin/', admin.site.urls),path('login/', views.login),path('index/', views.index), ] View Code修改views.py,增加視圖函數
from django.shortcuts import render,HttpResponse,redirect from django.contrib import auth # Create your views here. def login(request):if request.method == "POST":user = request.POST.get("user")pwd = request.POST.get("pwd")#用戶驗證成功,返回user對象,否則返回Noneret = auth.authenticate(username=user,password=pwd)print(ret)print(ret.__dict__)if ret:return redirect("/index/")return render(request,"login.html")def index(request):return render(request, "index.html") View Code在templates新建文件login.html
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Title</title> </head> <body> <form action="" method="post">{% csrf_token %}<lable>用戶名</lable><input type="text" name="user"><lable>密碼</lable><input type="password" name="pwd"><input type="submit"> </form> </body> </html> View Code新建文件index.html
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Title</title> </head> <body> <h3>HI.</h3> </body> </html> View Code訪問登錄頁面
?
跳轉首頁
?
查看Pycharm控制臺輸出
xiao {'email': '', 'last_login': None, 'is_superuser': True, 'is_staff': True, 'date_joined': datetime.datetime(2018, 7, 9, 11, 2, 16, 775761, tzinfo=<UTC>), 'last_name': '', '_state': <django.db.models.base.ModelState object at 0x000002E6F03447B8>, 'username': 'xiao', 'password': 'pbkdf2_sha256$100000$LAp6T0YPt6Xj$37j4PuLHs3W/HRjQQyn4KYZZQog9QWrbmatAB+PC6pM=', 'id': 1, 'backend': 'django.contrib.auth.backends.ModelBackend', 'is_active': True, 'first_name': ''} View Code?
?
1.2 、login(HttpRequest, user)
該函數接受一個HttpRequest對象,以及一個認證了的User對象
此函數使用django的session框架給某個已認證的用戶附加上session id等信息。
修改views.py
from django.shortcuts import render,HttpResponse,redirect from django.contrib import auth # Create your views here. def login(request):if request.method == "POST":user = request.POST.get("user")pwd = request.POST.get("pwd")#用戶驗證成功,返回user對象,否則返回Noneuser = auth.authenticate(username=user,password=pwd)# print(user)# print(user.__dict__)if user:#登錄,注冊session# 全局變量 request.user=當前登陸對象(session中) auth.login(request,user)return redirect("/index/")return render(request,"login.html")def index(request):print(request.user) # 默認是一個匿名對象print(request.user.id)print(request.user.username)return render(request, "index.html") View Code直接訪問index
?
查看Pycharm控制臺輸出:
AnonymousUser
None
?
request.user 默認是一個匿名對象,auth_user表的所有字段對應的值,都是空的。
當登錄成功之后,該對象才會有值。
訪問登錄頁面??http://127.0.0.1:8000/login/
重新登錄一次
查看Pycharm控制臺輸出:
xiao
1
xiao
?
request.user是全局變量,可以在任意代碼中運用
它用了一個中間件,在settings.py中的MIDDLEWARE配置項里
'django.contrib.auth.middleware.AuthenticationMiddleware',這句只要執行,那么就能注冊session,產生一個全局變量
auth.login(request,user)?
在上面的例子中,直接訪問首頁都可以,連登錄的省掉了,這是不對的。
加入判斷session
修改index視圖函數
def index(request):print(request.user) # 默認是一個匿名對象print(request.user.id)print(request.user.username)if not request.user.id:return redirect("/login/")name = request.user.usernamereturn render(request, "index.html",{"name":name}) View Code修改index.html
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Title</title> </head> <body> <h3>HI. {{ name }}</h3> </body> </html> View Code清空瀏覽器緩存
直接輸入url:?http://127.0.0.1:8000/index/
它會跳轉至登錄頁面,重新登錄后,效果如下:
它其實也有sessionid
使用火狐瀏覽器訪問
它會直接跳轉至登錄頁面
?
1.3 、logout(request) 注銷用戶
首頁添加注銷功能
修改urls.py,增加路徑logout
urlpatterns = [path('admin/', admin.site.urls),path('login/', views.login),path('index/', views.index),path('logout/', views.logout), ] View Code修改views.py,增加logout視圖函數
def logout(request): # 注銷auth.logout(request) # 清除session和cookiereturn redirect("/login/") View Code該函數接受一個HttpRequest對象,無返回值。當調用該函數時,當前請求的session信息會全部清除。該用戶即使沒有登錄,使用該函數也不會報錯。
?
修改index.html
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Title</title> </head> <body> <h3>HI. {{ name }} <a href="/logout/">注銷</a></h3> </body> </html> View Code?
點擊注銷
它會跳轉到登錄頁面
?
?查看logout源代碼
def logout(request):"""Remove the authenticated user's ID from the request and flush their sessiondata."""# Dispatch the signal before the user is logged out so the receivers have a# chance to find out *who* logged out.user = getattr(request, 'user', None)if hasattr(user, 'is_authenticated') and not user.is_authenticated:user = Noneuser_logged_out.send(sender=user.__class__, request=request, user=user)# remember language choice saved to sessionlanguage = request.session.get(LANGUAGE_SESSION_KEY)request.session.flush()if language is not None:request.session[LANGUAGE_SESSION_KEY] = languageif hasattr(request, 'user'):from django.contrib.auth.models import AnonymousUserrequest.user = AnonymousUser() View Code它其實和session清理類似,也是執行了命令
request.session.flush()但是在清理之前,它做了一些條件判斷!
注銷之后,request.user就是匿名用戶了!
注意:user是下面這行代碼。變量的名字而已(等式左邊的名字)
user = auth.authenticate(username=user,password=pwd)request.user不是固定寫法,根據變量名而變化!
?
User對象
User 對象屬性:username, password(必填項)password用哈希算法保存到數據庫?
?
2.1 、user對象的?is_authenticated()
如果是真正的 User 對象,返回值恒為 True 。 用于檢查用戶是否已經通過了認證。
通過認證并不意味著用戶擁有任何權限,甚至也不檢查該用戶是否處于激活狀態,這只是表明用戶成功的通過了認證。 這個方法很重要, 在后臺用request.user.is_authenticated()判斷用戶是否已經登錄,如果true則可以向前臺展示request.user.name
?
修改index視圖函數,更改判斷方式
def index(request):print(request.user) # 默認是一個匿名對象print(request.user.id)print(request.user.username)if not request.user.is_authenticated:return redirect("/login/")name = request.user.usernamereturn render(request, "index.html",{"name":name}) View Code注意:is_authenticated后面是沒有括號的,它返回一個布爾值!
?
清理瀏覽器緩存, 直接訪問index
會返回登錄頁面
?
2.2 、創建用戶
使用 create_user 輔助函數創建用戶:
修改urls.py,增加路徑adduser
urlpatterns = [path('admin/', admin.site.urls),path('login/', views.login),path('index/', views.index),path('logout/', views.logout),path('adduser/', views.adduser), ] View Code修改views.py,增加視圖函數adduser
必須導入模塊User
from django.contrib.auth.models import User這里用戶名和密碼寫死了,是為了方便測試,完整代碼如下:
from django.shortcuts import render,HttpResponse,redirect from django.contrib import auth from django.contrib.auth.models import User# Create your views here. def login(request):if request.method == "POST":user = request.POST.get("user")pwd = request.POST.get("pwd")#用戶驗證成功,返回user對象,否則返回Noneuser = auth.authenticate(username=user,password=pwd)# print(user)# print(user.__dict__)if user:#登錄,注冊session# 全局變量 request.user=當前登陸對象(session中) auth.login(request,user)return redirect("/index/")return render(request,"login.html")def index(request):print(request.user) # 默認是一個匿名對象print(request.user.id)print(request.user.username)if not request.user.is_authenticated:return redirect("/login/")name = request.user.usernamereturn render(request, "index.html",{"name":name})def logout(request): # 注銷auth.logout(request) # 清除session和cookiereturn redirect("/login/")def adduser(request):User.objects.create_superuser(username="zhang",password="123")return redirect("/login/") View Code?
直接訪問url:?http://127.0.0.1:8000/adduser/
它會直接跳轉至登錄頁面
沒關系,查看auth_user表記錄
發現is_superuser為0,表示為普通用戶
如果需要創建超級用戶,使用create_superuserf方法,比如:
User.objects.create_superuser(username="lisi",password="123")?
總結:5個接口
1 # 用戶驗證 成功:返回user對象,否則返回Noneuser=auth.authenticate(username=user, password=pwd) 2 # 登陸,注冊sessionauth.login(request,user) # 全局變量 request.user=當前登陸對象(session中)3 # 注銷 auth.logout(request)4 from django.contrib.auth.models import UserUser.objects.create_user(username="alex",password=123)5 request.user.is_authenticated View Coderequest.user它是全局變量,可以在模板中,直接渲染。
修改index.html
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Title</title> </head> <body> <h3>HI. {{ request.user.username }} <a href="/logout/">注銷</a></h3> </body> </html> View Code重新登錄,效果是一樣的!
request.user它有很多屬性,auth_user表中的字段,它都可以獲取。username只是其中一個屬性!
?
二、分頁器
批量導入數據
要想實現分頁,必須要有很多數據才行
使用Pycharm創建項目pageDemo
修改models.py,增加模型表Book
class Book(models.Model):title=models.CharField(max_length=32)price=models.DecimalField(max_digits=8,decimal_places=2) View Code執行2個命令,生成django需要的表
python manage.py makemigrations python manage.py migrate修改urls.py,增加路徑index
from app01 import views urlpatterns = [path('admin/', admin.site.urls),path('index/', views.index), ] View Code修改views.py,增加視圖函數index
def index(request):for i in range(100):Book.objects.create(title="book_%s"%i,price=i*i)使用上面的代碼生成100條數據,會很慢!為什么呢?它每次需要找到表,插入一條記錄。效率太低了!
使用bulk_create實現批量插入,效率更高!
修改index視圖函數,完整代碼如下:
from django.shortcuts import render,HttpResponse from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger from app01.models import Book # Create your views here. def index(request):book_list = [] # 定義空列表for i in range(100):book = Book(title="book_%s" % i, price=i * i)book_list.append(book) # 對象追加列表中 Book.objects.bulk_create(book_list) # 一次性批量插入100條記錄 View Code在templates目錄下創建文件index.html
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Title</title> </head> <body> <h3>INDEX</h3> </body> </html> View Code訪問首頁
?瞬間,頁面加載完了
?查看表記錄,發現有100條記錄了!
?
展示表數據
修改index視圖函數
def index(request):book_list = Book.objects.all()return render(request,"index.html",{"book_list":book_list}) View Code修改index.html
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Title</title> </head> <body> <h3>INDEX</h3> <ul>{% for book in book_list %}<li>{{ book.title }}-->{{ book.price }}</li>{% endfor %}</ul> </body> </html> View Code訪問首頁,發現有100條數據
這是100條數據,如果有1000萬條數據呢?瀏覽器打開,頁面會直接卡死!
下面來講如何使用分頁。
?
Django的分頁器(paginator)
Django提供了一個新的類來幫助你管理分頁數據,這個類存放在django/core/paginator.py.它可以接收列表、元組或其它可迭代的對象。
django-pagination就像它的名字一樣,它是一個Django分頁器,它包含了一組翻頁功能相關的utils,包括用于實現翻頁的tag等。使用起來非常簡單。是目前使用最多的分頁APP。
要使用Django實現分頁器,必須從Django中導入Paginator模塊
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger一頁顯示10條
修改index視圖函數
from django.shortcuts import render,HttpResponse from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger from app01.models import Book # Create your views here. def index(request):book_list = Book.objects.all()paginator = Paginator(book_list,10) # 每頁顯示10條print(paginator.count) #數據總數 100print(paginator.num_pages) # #總頁數 10 print(paginator.page_range) #頁碼的列表 range(1, 11) page_01 = paginator.page(2) #第2頁的所有數據對象print(page_01.has_next()) #是否有下一頁print(page_01.has_previous()) #是否有上一頁print(page_01.next_page_number()) #下一頁的頁碼print(page_01.previous_page_number()) #上一頁的頁碼return render(request,"index.html",{"page_01":page_01}) View Code修改index.html
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Title</title> </head> <body> <h3>INDEX</h3> <ul>{% for book in page_01 %}<li>{{ book.title }}-->{{ book.price }}</li>{% endfor %}</ul> </body> </html> View Code刷新網頁,這里展示的是第2頁的數據
?
Pycharm控制臺輸出:
100
10
range(1, 11)
True
True
3
1
?
注意:paginator.page(),這里面數字,如果超過頁碼數,會報錯!
EmptyPage at /index/
?
通過修改url的參數,就可以訪問任意頁的數據
修改index視圖函數
def index(request):book_list = Book.objects.all()paginator = Paginator(book_list,10) # 每頁顯示10條#當前頁碼,如果取不到page參數,默認為1current_num = int(request.GET.get("page",1))book_list = paginator.page(current_num)return render(request,"index.html",{"book_list":book_list}) View Code手動輸出url:?http://127.0.0.1:8000/index/?page=3
就可以訪問分頁數據了
超過頁碼,就會報錯
這樣用戶體驗不好,?展示頁面器,讓用戶能點擊!
?
展示頁面器
訪問Bootstrap,找到分頁。鏈接如下:
https://v3.bootcss.com/components/#pagination
copy默認分頁樣式
修改index視圖函數
def index(request):book_list = Book.objects.all()paginator = Paginator(book_list,10) # 每頁顯示10條# #當前頁碼,如果取不到page參數,默認為1current_num = int(request.GET.get("page",1)) # 當前頁碼book_list = paginator.page(current_num) # 展示當前頁碼的10條數據print(paginator.page_range) # 頁碼的列表return render(request,"index.html",{"book_list":book_list,"paginator":paginator}) View Code修改index.html
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Title</title><link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css"> </head> <body> <h3>INDEX</h3> {#數據展示#} <ul>{% for book in book_list %}<li>{{ book.title }}-->{{ book.price }}</li>{% endfor %}</ul> {#分頁展示#} <nav aria-label="Page navigation"><ul class="pagination"><li><a href="#" aria-label="Previous"><span aria-hidden="true">«</span></a></li>{#遍歷頁碼的列表#}{% for i in paginator.page_range %}{#href參數為簡寫,它會自動獲取當前路徑,并拼接參數#}<li><a href="?page={{ i }}">{{ i }}</a></li>{% endfor %}<li><a href="#" aria-label="Next"><span aria-hidden="true">»</span></a></li></ul> </nav> </body> </html> View Code刷新頁面,效果如下:
選中加深效果
思路:點擊一個頁碼,它會發送一次請求,參數就是點擊的數字。頁面會刷新一次!
那么只需要判斷url的參數等于當前頁面數,加一個class=active,就可以了!
修改index視圖函數,將current_num(當前頁碼數)傳給模板
def index(request):book_list = Book.objects.all()paginator = Paginator(book_list,10) # 每頁顯示10條# #當前頁碼,如果取不到page參數,默認為1current_num = int(request.GET.get("page",1)) # 當前頁碼book_list = paginator.page(current_num) # 展示當前頁碼的10條數據print(paginator.page_range) # 頁碼的列表return render(request,"index.html",{"book_list":book_list,"paginator":paginator,"current_num":current_num}) View Code修改index.html
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Title</title><link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css"> </head> <body> <h3>INDEX</h3> {#數據展示#} <ul>{% for book in book_list %}<li>{{ book.title }}-->{{ book.price }}</li>{% endfor %}</ul> {#分頁展示#} <nav aria-label="Page navigation"><ul class="pagination"><li><a href="#" aria-label="Previous"><span aria-hidden="true">«</span></a></li>{#遍歷頁碼的列表#}{% for i in paginator.page_range %}{#判斷當前頁碼數等于底部頁碼時#}{% if current_num == i %}{#增加class,加深按鈕#}<li class="active"><a href="?page={{ i }}">{{ i }}</a></li>{% else %}{#href參數為簡寫,它會自動獲取當前路徑,并拼接參數#}<li><a href="?page={{ i }}">{{ i }}</a></li>{% endif %}{% endfor %}<li><a href="#" aria-label="Next"><span aria-hidden="true">»</span></a></li></ul> </nav> </body> </html> View Code刷新頁面,效果如下:
注意:點擊頁碼之后,它會發送新請求,頁面會刷新,重新渲染。
?
上一頁
思路:上一頁,就是當前頁碼數減一就可以了!但是模板里面不能直接減一,所以使用過濾器
current_num|add:-1就可以得到上一頁了!但是paginator提供了方法previous_page_number,來獲取上一頁的頁碼
has_previous 判斷是否有上一頁
previous_page_number 上一頁的頁碼
?
注意:如果是第一頁,那么點擊上一頁之后,就會報錯!所以需要判斷,當是第一頁時,增加class="disabled",不讓用戶點擊!
修改index視圖函數
def index(request):book_list = Book.objects.all() # 讀取表中的所有數據paginator = Paginator(book_list,10) # 每頁顯示10條#異常判斷try:# 當前頁碼,如果取不到page參數,默認為1current_num = int(request.GET.get("page", 1)) # 當前頁碼book_list = paginator.page(current_num) # 獲取當前頁碼的10條數據except EmptyPage: # 頁碼不存在時,報EmptyPage錯誤book_list = paginator.page(1) # 強制更新為第一頁 data = {"book_list":book_list,"paginator":paginator,"current_num":current_num}return render(request,"index.html",data) View Code修改index.html
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Title</title><link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css"> </head> <body> <h3>INDEX</h3> {#數據展示#} <ul>{% for book in book_list %}<li>{{ book.title }}-->{{ book.price }}</li>{% endfor %}</ul> {#分頁展示#} <nav aria-label="Page navigation"><ul class="pagination">{#has_previous 判斷是否有上一頁#}{% if book_list.has_previous %}{#previous_page_number 上一頁的頁碼#}<li><a href="?page={{ book_list.previous_page_number }}" aria-label="Previous"><spanaria-hidden="true">上一頁</span></a></li>{% else %}{#class="disabled" 禁止用戶點擊#}<li class="disabled"><a href="" aria-label="Previous"><span aria-hidden="true">上一頁</span></a></li>{% endif %}{#遍歷頁碼的列表#}{% for i in paginator.page_range %}{#判斷當前頁碼數等于底部頁碼時#}{% if current_num == i %}{#增加class,加深按鈕#}<li class="active"><a href="?page={{ i }}">{{ i }}</a></li>{% else %}{#href參數為簡寫,它會自動獲取當前路徑,并拼接參數#}<li><a href="?page={{ i }}">{{ i }}</a></li>{% endif %}{% endfor %}<li><a href="#" aria-label="Next"><span aria-hidden="true">»</span></a></li></ul> </nav> </body> </html> View Code刷新頁面,效果如下:
?
下一頁
思路:使用paginator提供的方法
has_next 判斷是否有下一頁
next_page_number 下一頁的頁碼
修改index.html
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Title</title><link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css"> </head> <body> <h3>INDEX</h3> {#數據展示#} <ul>{% for book in book_list %}<li>{{ book.title }}-->{{ book.price }}</li>{% endfor %}</ul> {#分頁展示#} <nav aria-label="Page navigation"><ul class="pagination">{#has_previous 判斷是否有上一頁#}{% if book_list.has_previous %}{#previous_page_number 上一頁的頁碼#}<li><a href="?page={{ book_list.previous_page_number }}" aria-label="Previous"><spanaria-hidden="true">上一頁</span></a></li>{% else %}{#class="disabled" 禁止用戶點擊#}<li class="disabled"><a href="" aria-label="Previous"><span aria-hidden="true">上一頁</span></a></li>{% endif %}{#遍歷頁碼的列表#}{% for i in paginator.page_range %}{#判斷當前頁碼數等于底部頁碼時#}{% if current_num == i %}{#增加class,加深按鈕#}<li class="active"><a href="?page={{ i }}">{{ i }}</a></li>{% else %}{#href參數為簡寫,它會自動獲取當前路徑,并拼接參數#}<li><a href="?page={{ i }}">{{ i }}</a></li>{% endif %}{% endfor %}{#has_next 判斷是否有下一頁#}{% if book_list.has_next %}{#next_page_number 下一頁的頁碼#}<li><a href="?page={{ book_list.next_page_number }}" aria-label="Next"><spanaria-hidden="true">下一頁</span></a></li>{% else %}{#class="disabled" 禁止用戶點擊#}<li class="disabled"><a href="" aria-label="Next"><span aria-hidden="true">下一頁</span></a></li>{% endif %}</ul> </nav> </body> </html> View Code刷新頁面,效果如下:
?
首頁和最后一頁
思路:首頁為:page=1,最后一頁為:page={{ paginator.num_pages }}
paginator.num_pages表示總頁數
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Title</title><link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css"> </head> <body> <h3>INDEX</h3> {#數據展示#} <ul>{% for book in book_list %}<li>{{ book.title }}-->{{ book.price }}</li>{% endfor %}</ul> {#分頁展示#} <nav aria-label="Page navigation"><ul class="pagination"><li><a href="?page=1" aria-label="Previous"><span aria-hidden="true">首頁</span></a></li>{#has_previous 判斷是否有上一頁#}{% if book_list.has_previous %}{#previous_page_number 上一頁的頁碼#}<li><a href="?page={{ book_list.previous_page_number }}" aria-label="Previous"><spanaria-hidden="true">上一頁</span></a></li>{% else %}{#class="disabled" 禁止用戶點擊#}<li class="disabled"><a href="" aria-label="Previous"><span aria-hidden="true">上一頁</span></a></li>{% endif %}{#遍歷頁碼的列表#}{% for i in paginator.page_range %}{#判斷當前頁碼數等于底部頁碼時#}{% if current_num == i %}{#增加class,加深按鈕#}<li class="active"><a href="?page={{ i }}">{{ i }}</a></li>{% else %}{#href參數為簡寫,它會自動獲取當前路徑,并拼接參數#}<li><a href="?page={{ i }}">{{ i }}</a></li>{% endif %}{% endfor %}{#has_next 判斷是否有下一頁#}{% if book_list.has_next %}{#next_page_number 下一頁的頁碼#}<li><a href="?page={{ book_list.next_page_number }}" aria-label="Next"><spanaria-hidden="true">下一頁</span></a></li>{% else %}{#class="disabled" 禁止用戶點擊#}<li class="disabled"><a href="" aria-label="Next"><span aria-hidden="true">下一頁</span></a></li>{% endif %}<li><a href="?page={{ paginator.num_pages }}" aria-label="Next"><span aria-hidden="true">最后一頁</span></a></li></ul> </nav> </body> </html> View Code效果如下:
?固定顯示11頁
修改index視圖函數,改一行代碼,每頁顯示2條數據
paginator = Paginator(book_list,2)刷新網頁,效果如下:
?從頁面中可以看出,展示了50頁。這樣非常影響頁面排版,用戶體驗也不好!
一般網站會展示11頁,比如博客園首頁的分頁器,效果如下:
11頁怎么計算的呢?左5頁,右5頁,加上當前頁,共11頁!
?
修改index視圖函數,完整代碼如下:
from django.shortcuts import render,HttpResponse from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger from app01.models import Book # Create your views here. def index(request):book_list = Book.objects.all() # 讀取表中的所有數據paginator = Paginator(book_list,2) # 每頁顯示2條#異常判斷try:# 當前頁碼,如果取不到page參數,默認為1current_num = int(request.GET.get("page", 1)) # 當前頁碼book_list = paginator.page(current_num) # 獲取當前頁碼的數據except EmptyPage: # 頁碼不存在時,報EmptyPage錯誤book_list = paginator.page(1) # 強制更新為第一頁# 如果頁數十分多時,換另外一種顯示方式if paginator.num_pages > 11: # 一般網頁展示11頁,左5頁,右5頁,加上當前頁,共11頁if current_num - 5 < 1: # 如果前5頁小于1時pageRange = range(1, 11) # 頁碼的列表:范圍是初始狀態elif current_num + 5 > paginator.num_pages: # 如果后5頁大于總頁數時# 頁碼的列表:范圍是(當前頁-5,總頁數+1)。因為range顧頭不顧尾,需要加1pageRange = range(current_num - 5, paginator.num_pages + 1)else:# 頁碼的列表:后5頁正常時,頁碼范圍是(當前頁-5,當前頁+6)。注意不是+5,因為range顧頭不顧尾!pageRange = range(current_num - 5, current_num + 6)else:pageRange = paginator.page_range # 頁碼的列表 data = {"book_list":book_list,"paginator":paginator,"current_num":current_num,"pageRange":pageRange}return render(request,"index.html",data) View Code修改index.html,修改for循環的變量
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Title</title><link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css"> </head> <body> <h3>INDEX</h3> {#數據展示#} <ul>{% for book in book_list %}<li>{{ book.title }}-->{{ book.price }}</li>{% endfor %}</ul> {#分頁展示#} <nav aria-label="Page navigation"><ul class="pagination"><li><a href="?page=1" aria-label="Previous"><span aria-hidden="true">首頁</span></a></li>{#has_previous 判斷是否有上一頁#}{% if book_list.has_previous %}{#previous_page_number 上一頁的頁碼#}<li><a href="?page={{ book_list.previous_page_number }}" aria-label="Previous"><spanaria-hidden="true">上一頁</span></a></li>{% else %}{#class="disabled" 禁止用戶點擊#}<li class="disabled"><a href="" aria-label="Previous"><span aria-hidden="true">上一頁</span></a></li>{% endif %}{#遍歷頁碼的列表#}{% for i in pageRange %}{#判斷當前頁碼數等于底部頁碼時#}{% if current_num == i %}{#增加class,加深按鈕#}<li class="active"><a href="?page={{ i }}">{{ i }}</a></li>{% else %}{#href參數為簡寫,它會自動獲取當前路徑,并拼接參數#}<li><a href="?page={{ i }}">{{ i }}</a></li>{% endif %}{% endfor %}{#has_next 判斷是否有下一頁#}{% if book_list.has_next %}{#next_page_number 下一頁的頁碼#}<li><a href="?page={{ book_list.next_page_number }}" aria-label="Next"><spanaria-hidden="true">下一頁</span></a></li>{% else %}{#class="disabled" 禁止用戶點擊#}<li class="disabled"><a href="" aria-label="Next"><span aria-hidden="true">下一頁</span></a></li>{% endif %}<li><a href="?page={{ paginator.num_pages }}" aria-label="Next"><span aria-hidden="true">最后一頁</span></a></li></ul> </nav> </body> </html> View Code刷新網頁,效果如下:
?
轉載于:https://www.cnblogs.com/xiao987334176/p/9285629.html
總結
以上是生活随笔為你收集整理的python 全栈开发,Day79(Django的用户认证组件,分页器)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 9
- 下一篇: websocket python爬虫_p