本文将为您提供关于Django;如何更改django.contrib.sessions使用的表名?的详细介绍,我们还将为您解释django修改admin页面的相关知识,同时,我们还将为您提供关于12D
本文将为您提供关于Django;如何更改django.contrib.sessions使用的表名?的详细介绍,我们还将为您解释django修改admin页面的相关知识,同时,我们还将为您提供关于12 Django cooking与session、25 Jun 18 Django,Cookie,Session,分页(自定义,Django自带)、Django - cookie & session、Django - Cookie、Session、自定义分页和Django分页器的实用信息。
本文目录一览:- Django;如何更改django.contrib.sessions使用的表名?(django修改admin页面)
- 12 Django cooking与session
- 25 Jun 18 Django,Cookie,Session,分页(自定义,Django自带)
- Django - cookie & session
- Django - Cookie、Session、自定义分页和Django分页器
Django;如何更改django.contrib.sessions使用的表名?(django修改admin页面)
我如何在’django.contrib.sessions.models’中的Meta类中更改信息,以便我的项目可以具有统一的表名,但应用程序的功能相同?
谢谢
答案1
小编典典您可以尝试以下方法:
from django.contrib.sessions.models import SessionSession.Meta.db_table = ''my_session''
编辑 以上解决方案会引发错误,但可以进行以下工作:
from django.contrib.sessions.models import SessionSession._meta.db_table = "my_session"
12 Django cooking与session
一.会话跟踪技术
1.什么是会话跟踪技术
我们需要先了解一下什么是会话!可以把会话理解为客户端与服务器之间的一次会晤,在一次会晤中可能会包含多次请求和响应。例如你给10086打个电话,你就是客户端,而10086服务人员就是服务器了。从双方接通电话那一刻起,会话就开始了,到某一方挂断电话表示会话结束。在通话过程中,你会向10086发出多个请求,那么这多个请求都在一个会话中。
在JavaWeb中,客户向某一服务器发出第一个请求开始,会话就开始了,直到客户关闭了浏览器会话结束.
在一个会话的多个请求中共享数据,这就是会话跟踪技术;例如在一个会话中的请求如下:
- 请求银行主页;
- 请求登陆(请求参数是用户名和没密码);
- 请求转账(请求参数与转账相关的数据);
- 请求信用卡还款(请求参数与还款相关的数据)
在这上会话中当前用户信息必须在这个会话中共享的,因为登录的是张三,那么在转账和还款时一定是相对张三的转账和还款!这就说明我们必须在一个会话过程中有共享数据的能力。
2.会话路径技术使用Cookie或session完成
我们知道HTTP协议是无状态协议,也就是说每个请求都是独立的!无法记录前一次请求的状态。但HTTP协议中可以使用Cookie来完成会话跟踪!在Web开发中,使用session来完成会话跟踪,session底层依赖Cookie技术.
二.Cookie概述
1.什么是Cookie
Cookie翻译成中文是小甜点,小饼干的意思。在HTTP中它表示服务器送给客户端浏览器的小甜点。其实Cookie是key-value结构,类似于一个python中的字典。随着服务器端的响应发送给客户端浏览器。然后客户端浏览器会把Cookie保存起来,当下一次再访问服务器时把Cookie再发送给服务器。 Cookie是由服务器创建,然后通过响应发送给客户端的一个键值对。客户端会保存Cookie,并会标注出Cookie的来源(哪个服务器的Cookie)。当客户端向服务器发出请求时会把所有这个服务器Cookie包含在请求中发送给服务器,这样服务器就可以识别客户端了!
2.Cookie规范
- Cookie大小上限为4KB
- 一个服务器最多在客户端上保存20个Cookie
- 一个浏览器最多保存300个Cookie
上面的数据只是HTTP的Cookie规范,但在浏览器大战的今天,一些浏览器为了打败对手,为了展现自己的能力起见,可能对Cookie规范“扩展”了一些,例如每个Cookie的大小为8KB,最多可保存500个Cookie等!但也不会出现把你硬盘占满的可能!
注意,不同浏览器之间是不共享Cookie的。也就是说在你使用IE访问服务器时,服务器会把Cookie发给IE,然后由IE保存起来,当你在使用FireFox访问服务器时,不可能把IE保存的Cookie发送给服务器。
3.Cookie与HTTP头
Cookie是通过HTTP请求和响应头在客户端和服务端传递的:
- Cookie:请求头,客户端发送给服务器端
- 格式:Cookie:a=A; b=B; c=C。即多个Cookie用分号隔开;
- Set-Cookie:响应头,服务端发送给客户端;
- 一个Cookie对象一个Set-Cookie: Set-Cookie: a=A Set-Cookie: b=B Set-Cookie: c=C
4.Cookie的覆盖
如果服务器端发送重复的Cookie那么会覆盖原有的Cookie,例如客户端的第一个请求服务器端发送的Cookie是:Set-Cookie: a=A;第二请求服务器端发送的是:Set-Cookie: a=AA,那么客户端只留下一个Cookie,即:a=AA。
5.Django中的Cookie语法
(1).设置Cookie:
rep = HttpResponse(...) 或 rep = render(request, ...) 或 rep = redirect()
rep.set_cookie(key,value,...)
rep.set_signed_cookie(key,value,salt=''加密盐'',...)
(2).源码:
''''''
class HttpResponseBase:
def set_cookie(self, key, 键
value='''', 值
max_age=None, 超长时间
cookie需要延续的时间(以秒为单位)
如果参数是\ None`` ,这个cookie会延续到浏览器关闭为止。
expires=None, 超长时间
expires默认None ,cookie失效的实际日期/时间。
path=''/'', Cookie生效的路径,
浏览器只会把cookie回传给带有该路径的页面,这样可以避免将
cookie传给站点中的其他的应用。
/ 表示根路径,特殊的:根路径的cookie可以被任何url的页面访问
domain=None, Cookie生效的域名
你可用这个参数来构造一个跨站cookie。
如, domain=".example.com"
所构造的cookie对下面这些站点都是可读的:
www.example.com 、 www2.example.com
和an.other.sub.domain.example.com 。
如果该参数设置为 None ,cookie只能由设置它的站点读取。
secure=False, 如果设置为 True ,浏览器将通过HTTPS来回传cookie。
httponly=False 只能http协议传输,无法被JavaScript获取
(不是绝对,底层抓包可以获取到也可以被覆盖)
): pass
''''''
(3).获取Cookie:
request.COOKIES
(4).删除Cookie
response.delete_cookie("cookie_key",path="/",domain=name)
三.session
Session是服务器端技术,利用这个技术,服务器在运行时可以 为每一个用户的浏览器创建一个其独享的session对象,由于 session为用户浏览器独享,所以用户在访问服务器的web资源时 ,可以把各自的数据放在各自的session中,当用户再去访问该服务器中的其它web资源时,其它web资源再从用户各自的session中 取出数据为用户服务。
1.Django中的session语法
1、设置Sessions值
request.session[''session_name''] ="admin"
2、获取Sessions值
session_name = request.session["session_name"]
3、删除Sessions值
del request.session["session_name"]
4、flush()
删除当前的会话数据并删除会话的Cookie。
这用于确保前面的会话数据不可以再次被用户的浏览器访问


5、get(key, default=None)
fav_color = request.session.get(''fav_color'', ''red'')
6、pop(key)
fav_color = request.session.pop(''fav_color'')
7、keys()
8、items()
9、setdefault()
10 用户session的随机字符串
request.session.session_key
# 将所有Session失效日期小于当前日期的数据删除
request.session.clear_expired()
# 检查 用户session的随机字符串 在数据库中是否
request.session.exists("session_key")
# 删除当前用户的所有Session数据
request.session.delete("session_key")
request.session.set_expiry(value)
* 如果value是个整数,session会在几秒数后失效。
* 如果value是个datatime或timedelta,session就会在这个时间后失效。
* 如果value是0,用户关闭浏览器session就会失效。
* 如果value是None,session会依赖全局session失效策略。
2.session配置


Django默认支持Session,并且默认是将Session数据存储在数据库中,即:django_session 表中。
a. 配置 settings.py
SESSION_ENGINE = ''django.contrib.sessions.backends.db'' # 引擎(默认)
SESSION_COOKIE_NAME = "sessionid" # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串(默认)
SESSION_COOKIE_PATH = "/" # Session的cookie保存的路径(默认)
SESSION_COOKIE_DOMAIN = None # Session的cookie保存的域名(默认)
SESSION_COOKIE_SECURE = False # 是否Https传输cookie(默认)
SESSION_COOKIE_HTTPONLY = True # 是否Session的cookie只支持http传输(默认)
SESSION_COOKIE_AGE = 1209600 # Session的cookie失效日期(2周)(默认)
SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 是否关闭浏览器使得Session过期(默认)
SESSION_SAVE_EVERY_REQUEST = False # 是否每次请求都保存Session,默认修改之后才保存(默认)
25 Jun 18 Django,Cookie,Session,分页(自定义,Django自带)
25 Jun 18
https://www.cnblogs.com/liwenzhou/p/8343243.html
一、分页
# 利用URL携带参数page,views.py中通过request.GET来获取page参数
# utils: 放常用工具
- 在工具包utils中自定义mypage,并用其完成分页显示(推荐使用)
book_list.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Book_list</title>
<link rel="stylesheet" href="/static/bootstrap-3.3.7/css/bootstrap.min.css">
</head>
<body>
<h1>Book List</h1>
<div>
<table>
<thead>
<tr>
<th>#</th>
<th>Title</th>
<th>Publish Date</th>
</tr>
</thead>
<tbody>
{% for book in book_list %}
<tr>
<td>{{ forloop.counter }}</td>
<td>{{ book.title }}</td>
<td>{{ book.publish_date|date:''Y-m-d''}}</td> # 格式化输出日期
</tr>
{% endfor %}
</tbody>
</table>
</div>
<nav aria-label="Page navigation">
<ul>
{{ page_html|safe}} # 取消浏览器自动转译功能
</ul>
</nav>
<script src="/static/jquery-3.3.1.min.js"></script>
<script src="/static/bootstrap-3.3.7/js/bootstrap.min.js"></script>
</body>
</html>
views.py
from django.shortcuts import render
from app01 import models
from utils import mypage
# 用工具包utils中的自定义mypage,完成分页显示
def book_list(request):
data = models.Book.objects.all()
total_num = data.count()
current_page = request.GET.get(''page'')
page_obj=mypage.Page(total_num, current_page, ''book_list'',per_page=20)
book_list = data[page_obj.data_start:page_obj.data_end]
page_html = page_obj.page_html()
return render(request, "book_List.html", {''book_list'':book_list, ''page_html'':page_html})
utils -> mypage.py. (小工具,可反复使用)
class Page(object):
"""
这是一个自定义分页类
可以实现Django ORM数据的分页展示
使用说明:
from utils import mypage
page_obj = mypage.Page(total_num, current_page, ''publisher_list'')
publisher_list = data[page_obj.data_start:page_obj.data_end]
page_html = page_obj.page_html()
为了显示效果,show_page_num最好使用奇数 #当前页面highlight,左右对称排列
"""
def __init__(self, total_num, current_page, url_prefix, per_page=10, show_page_num=11):
"""
:param total_num: 数据的总条数
:param current_page: 当前访问的页码
:param url_prefix: 分页代码里a标签的前缀
:param per_page: 每一页显示多少条数据
:param show_page_num: 页面上最多显示多少个页码
"""
self.total_num = total_num
self.url_prefix = url_prefix
self.per_page = per_page
self.show_page_num = show_page_num
self.half_show_page_num = self.show_page_num // 2
total_page, more = divmod(self.total_num, self.per_page) # divmod()得到商和余数的小元组
if more:
total_page += 1
self.total_page = total_page
try:
current_page = int(current_page) # GET得到的current_page是字符串,必须要转成int才能进行后续运算操作
except Exception as e:
current_page = 1
if current_page > self.total_page:
current_page = self.total_page
if current_page < 1:
current_page = 1
self.current_page = current_page
if self.current_page - self.half_show_page_num <= 1:
page_start = 1
page_end = self.show_page_num
elif self.current_page + self.half_show_page_num >= self.total_page:
page_end = self.total_page
page_start = self.total_page - self.show_page_num + 1
else:
page_start = self.current_page - self.half_show_page_num
page_end = self.current_page + self.half_show_page_num
self.page_start = page_start
self.page_end = page_end
@property # 将方法装饰成数据属性
def data_start(self):
return (self.current_page-1)*self.per_page
@property
def data_end(self):
return (self.current_page)*self.per_page
def page_html(self):
li_list = []
li_list.append(''<li><a href="/{}/?page=1">首页</a></li>''.format(self.url_prefix))
if self.current_page <= 1:
prev_html = ''<li ><a aria-label="Previous"><span aria-hidden="true">«</span></a></li>'' # disabled,当在第一页时不能选前一页
else:
prev_html = ''<li><a href="/{}/?page={}" aria_label="Previous"><span aria-hidden="true">«</span></a></li>''.format(
self.url_prefix,self.current_page - 1)
li_list.append(prev_html)
for i in range(self.page_start, self.page_end + 1):
if i == self.current_page:
tmp = ''<li ><a href="/{0}/?page={1}">{1}</a></li>''.format(self.url_prefix,i)# active,当前页highlight
else:
tmp = ''<li><a href="/{0}/?page={1}">{1}</a></li>''.format(self.url_prefix,i)
li_list.append(tmp)
if self.current_page >= self.total_page:
next_html = ''<li><a aria-label="Previous"><span aria-hidden="true">»</span></a></li>''
else:
next_html = ''<li><a href="/{}/?page={}" aria_label="Previous"><span aria-hidden="true">»</span></a></li>''.format(
self.url_prefix, self.current_page + 1)
li_list.append(next_html)
li_list.append(''<li><a href="/{}/?page={}">尾页</a></li>''.format(self.url_prefix,self.total_page))
page_html = "".join(li_list) # 连成一个大的字符串,传至前段,方便后续操作
return page_html
- 用Django中的分页,完成显示
views.py
# 用django中的工具,完成分页显示;功能单薄,一般不用
from django.core.paginator import Paginator,EmptyPage,PageNotAnInteger
def publisher_list(request):
data = models.Publisher.objects.all()
current_page = request.GET.get(''page'')
page_obj = Paginator(data,10)
try:
publisher_list = page_obj.page(current_page)
# has_next 是否有下一页
# next_page_number 下一页页码
# has_previous 是否有上一页
# previous_page_number 上一页页码
# object_list 分页之后的数据列表
# number 当前页
# paginator paginator对象
except PageNotAnInteger:
publisher_list= page_obj.page(1)
except EmptyPage:
publisher_list = page_obj.page(page_obj.num_pages)
return render(request,''publisher_list.html'',{''publisher_list'':publisher_list})
publisher_list.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Publisher_list</title>
<link rel="stylesheet" href="/static/bootstrap-3.3.7/css/bootstrap.min.css">
</head>
<body>
<h1>Publisher List</h1>
<div>
<table>
<thead>
<tr>
<th>#</th>
<th>Publish Name</th>
</tr>
</thead>
<tbody>
{% for publisher in publisher_list %}
<tr>
<td>{{ forloop.counter }}</td>
<td>{{ publisher.name }}</td>
</tr>
{% endfor %}
</tbody>
</table>
<nav aria-label="Page navigation">
<ul>
{% if publisher_list.has_previous%}
<li>
<a href="/publisher_list/?page={{ publisher_list.previous_page_number}}" aria-label="Previous">
<span aria-hidden="true">«</span>
</a>
</li>
{% else %}
<li>
<a aria-label="Previous">
<span aria-hidden="true">«</span>
</a>
</li>
{% endif %}
<li><a href="#">{{ publisher_list.number }}</a></li>
{% if publisher_list.has_next%}
<li>
<a href="/publisher_list/?page={{ publisher_list.next_page_number}}" aria-label="Next">
<span aria-hidden="true">»</span>
</a>
</li>
{% else %}
<li>
<a aria-label="Next">
<span aria-hidden="true">»</span>
</a>
</li>
{% endif %}
</ul>
</nav>
</div>
<script src="/static/jquery-3.3.1.min.js"></script>
<script src="/static/bootstrap-3.3.7/js/bootstrap.min.js"></script>
</body>
二、Cookie
HTTP无状态-> Cookie
Cookie:服务端在返回响应的时候设置的,保存在浏览器上的键值对。
复习:
print(request.path_info) # 获得路径
print(request.get_full_path()) # 获得路径+参数
login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Title</title>
</head>
<body>
<form action="{{ request.get_full_path }}" method="post">
{% csrf_token %}
<p>Username: <input type="text" name = "username"></p>
<p>Password: <input type="password" name="pwd"></p>
<p><input type="submit" value="Login"></p>
</form>
</body>
</html>
views.py
from django.shortcuts import render
from django.shortcuts import HttpResponse,render,redirect
from app01 import models
from utils import mypage
# 定义一个检测是否登陆的装饰器
def check_login(func):
def wrapper(request,*args,**kwargs):
login_flag = request.get_signed_cookie("login",default="",salt="shanghais1hao") # 获取Cookie,加盐版的盐要一致
# login_flag = request.COOKIES.get("login", "")
#获取Cookie,非加盐版
# default: 默认值
# salt: 加密盐
# max_age: 后台控制过期时间
if login_flag.upper() == ''OK'':
return func(request,*args,**kwargs)
else:
url = request.path_info # 获取跳转源路径
return redirect("/login/?next={}".format(url)) # 如果是从其他页面跳转来,记录下该页面,完成验证后跳转回去
return wrapper
# 用工具包utils中的自定义mypage,完成分页显示
@check_login
def book_list(request):
data = models.Book.objects.all()
total_num = data.count()
current_page = request.GET.get(''page'')
page_obj=mypage.Page(total_num, current_page, ''book_list'',per_page=20)
book_list = data[page_obj.data_start:page_obj.data_end]
page_html = page_obj.page_html()
return render(request, "book_List.html", {''book_list'':book_list, ''page_html'':page_html})
def login(request):
if request.method == ''POST'':
username = request.POST.get(''username'')
pwd = request.POST.get(''pwd'')
if username == ''alex'' and pwd ==''alex'':
url = request.GET.get(''next'') # 如果是从其他页面跳转来,跳转至该页面
if not url:
url = ''/publisher_list/'' # 若非从其他页面跳转来的,跳转到默认页面
rep = redirect(url)
rep.set_signed_cookie("login","ok",salt="shanghais1hao")
# 给响应设置Cookie,加密盐版
# rep.set_cookie("login", "ok")
# 给响应设置Cookie
# key, 键
# value = '''', 值
# max_age = None, 超时时间
# expires = None, 超时时间(IE requires expires, so set it if hasn''t been already.)
# path = ''/'', Cookie生效的路径,/ 表示根路径,特殊的:根路径的cookie可以被任何url的页面访问
# domain = None, Cookie生效的域名
# secure = False, https传输
# httponly = False 只能http协议传输,无法被JavaScript获取(不是绝对,底层抓包可以获取到也可以被覆盖)
return rep
return render(request,"login.html")
def logout(request):
rep = redirect(''/login/'')
rep.delete_cookie(''login'') # 删除用户浏览器上之前设置的cookie值
return rep
三、Session
Cookie虽然在一定程度上解决了“保持状态”的需求,但是由于Cookie本身最大支持4096字节,以及Cookie本身保存在客户端,可能被拦截或窃取,因此就需要有一种新的东西,它能支持更多的字节,并且他保存在服务器,有较高的安全性。这就是Session。
# 用session前要现有一个数据库(一定要执行makemigrations, migrate两条命令,即使models无变化)
1. 浏览器请求来了之后,服务端给你分配一个序号(口令)(程序级别完成)
2. 浏览器收到响应之后,把得到的口令保存在cookie (浏览器自带)
3. 浏览器携带着刚才得到的口令,再次发送请求 (浏览器自带)
4. 服务端拿到口令,去后端根据口令找对应的数据(大字典)(程序级别完成)
views.py
def login(request):
err_msg = ""
if request.method == ''POST'':
username = request.POST.get(''username'')
pwd = request.POST.get(''pwd'')
is_exist = models.User.objects.filter(name=username,pwd=pwd)
if is_exist:
# 登陆成功
# 1. 生成随机字符串(口令),给浏览器返回
# 2. 在服务端开辟一块空间,用来保存对应的session数据(大字典)
# 3. 在服务端开辟的空间中保存需要保存的键值对数据
request.session[''login''] = ''OK''
request.session[''user''] = username # 可以插入不只一条数据
request.session.set_expiry(60*60*24*14) # 两周,python支持上述写法
return redirect(''/index/'')
else:
err_msg = ''invalid username or password''
return render(request,''login.html'',{''err_msg'':err_msg})
def index(request):
# 1. 判断请求中是否携带了我下发的随机字符串(口令)
# 2. 拿着口令去后端找对应的session数据
# 3. 根据固定的key去取固定的值
login_flag = request.session.get(''login'')
if login_flag == ''OK'':
return render(request,''index.html'')
else:
return redirect(''/login/'')
def logout(request):
request.session.flush() # 删除当前的会话数据并删除会话的Cookie
return redirect(''/login/'')
总结:
# 获取、设置、删除Session中数据
request.session[''k1'']
request.session.get(''k1'',None)
request.session[''k1''] = 123
request.session.setdefault(''k1'',123) # 存在则不设置
del request.session[''k1'']
# 所有 键、值、键值对
request.session.keys()
request.session.values()
request.session.items()
request.session.iterkeys()
request.session.itervalues()
request.session.iteritems()
# 会话session的key
request.session.session_key
# 将所有Session失效日期小于当前日期的数据删除
request.session.clear_expired() # session数据库中的数据不会自动清除,需手动删除
# 检查会话session的key在数据库中是否存在
request.session.exists("session_key")
# 删除当前会话的所有Session数据
request.session.delete()
# 删除当前的会话数据并删除会话的Cookie。
request.session.flush() # 推荐使用
这用于确保前面的会话数据不可以再次被用户的浏览器访问
例如,django.contrib.auth.logout() 函数中就会调用它。
# 设置会话Session和Cookie的超时时间
request.session.set_expiry(value)
* 如果value是个整数,session会在些秒数后失效。
* 如果value是个datatime或timedelta,session就会在这个时间后失效。
* 如果value是0,用户关闭浏览器session就会失效。
* 如果value是None,session会依赖全局session失效策略。
四、CBV中加装饰器(Django内置的把函数装饰器转换成方法装饰器)
方式一:加载CBV视图的get或post方法上
views.py
from django import views
from django.utils.decorators import method_decorator
class Home(views.View):
@method_decorator(check_login)
def get(self, request):
return render(request, "home.html")
def post(self):
pass
urls.py
urlpatterns = [
url(r''^home/'',views.Home.as_view()),
]
方式二:加载dispatch方法上
# 因为CBV中首先执行的就是dispatch方法,所以这么写相当于给get和post方法都加上了登录校验。
from django.utils.decorators import method_decorator
class HomeView(View):
@method_decorator(check_login)
def dispatch(self, request, *args, **kwargs):
return super(HomeView, self).dispatch(request, *args, **kwargs)
def get(self, request):
return render(request, "home.html")
def post(self, request):
print("Home View POST method...")
return redirect("/index/")
方式三:直接加在视图类上,但method_decorator必须传name 关键字参数
from django.utils.decorators import method_decorator
@method_decorator(check_login, name="get")
@method_decorator(check_login, name="post")
class HomeView(View):
def dispatch(self, request, *args, **kwargs):
return super(HomeView, self).dispatch(request, *args, **kwargs)
def get(self, request):
return render(request, "home.html")
def post(self, request):
print("Home View POST method...")
return redirect("/index/")
五、CSRF Token相关装饰器(csrf_exempt,csrf_protect)
CSRF Token相关装饰器在CBV只能加到dispatch方法上
csrf_protect:为当前函数强制设置防跨站请求伪造功能,即便settings没设置全局中间件。
csrf_exempt,取消当前函数防跨站请求伪造功能,即便settings中设置了全局中间件。
views.py
from django.views.decorators.csrf import csrf_exempt, csrf_protect
@csrf_exempt
def login(request):
err_msg = ""
if request.method == ''POST'':
username = request.POST.get(''username'')
pwd = request.POST.get(''pwd'')
is_exist = models.User.objects.filter(name=username,pwd=pwd)
if is_exist:
# 登陆成功
# 1. 生成随机字符串(口令),给浏览器返回
# 2. 在服务端开辟一块空间,用来保存对应的session数据(大字典)
# 3. 在服务端开辟的空间中保存需要保存的键值对数据
request.session[''login''] = ''OK''
request.session[''user''] = username # 可以插入不只一条数据
request.session.set_expiry(60*60*24*14) # 两周,python支持上述写法
return redirect(''/index/'')
else:
err_msg = ''invalid username or password''
return render(request,''login.html'',{''err_msg'':err_msg})
logins.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Title</title>
</head>
<body>
<form action="{{ request.get_full_path }}" method="post">
{# {% csrf_token %}#}
<p>Username: <input type="text" name = "username"></p>
<p>Password: <input type="password" name="pwd"></p>
<p><input type="submit" value="Login"></p>
<p>{{ err_msg }}</p>
</form>
</body>
</html>
六、其他
[链接]2018年不容错过的Django全栈项目YaDjangoBlog
https://zhuanlan.zhihu.com/p/33903527
七、补充
Django - cookie & session
主要内容:
- 1.cookie
- 2.session
1.cookie
1.1 cookie的概述
(1) cookie的由来
由于HTTP协议是无状态的。
- 无状态的意思是每次请求都是独立的,它的执行情况和结果与前面的请求和之后的请求都无直接关系,它不会受前面的请求响应情况直接影响,也不会直接影响后面的请求响应情况。
- 一句有意思的话来描述就是人生只如初见,对服务器来说,每次的请求都是全新的。
- 状态可以理解为客户端和服务器在某次会话中产生的数据,那无状态的就以为这些数据不会被保留。会话中产生的数据又是我们需要保存的,也就是说要“保持状态”。因此Cookie就是在这样一个场景下诞生。
(2) cookie的定义
Cookie具体指的是一段小信息,它是服务器发送出来存储在浏览器上的一组组键值对,下次访问服务器时浏览器会自动携带这些键值对,以便服务器提取有用信息。
(3)cookie的原理
cookie的工作原理是:由服务器产生内容,浏览器收到请求后保存在本地;当浏览器再次访问时,浏览器会自动带上Cookie,这样服务器就能通过Cookie的内容来判断这个是“谁”了。
1.2 Django中操作cookie
(1)获取cookie
request.COOKIES[''key'']
request.get_signed_cookie(''key'', default=RAISE_ERROR, salt='''', max_age=None)
get_signed_cookie方法的参数:
- default: 默认值
- salt: 加密盐
- max_age: 后台控制过期时间
(2)设置cookie
rep = HttpResponse(...)
rep = render(request, ...)
rep.set_cookie(key,value,...)
rep.set_signed_cookie(key,value,salt=''加密盐'',...)
参数:
- key, 键
- value='''', 值
- max_age=None, 超时时间
- expires=None, 超时时间(IE requires expires, so set it if hasn''t been already.)
- path=''/'', Cookie生效的路径,/ 表示根路径,特殊的:根路径的cookie可以被任何url的页面访问
- domain=None, Cookie生效的域名
- secure=False, https传输
- httponly=False 只能http协议传输,无法被JavaScript获取(不是绝对,底层抓包可以获取到也可以被覆盖)
(3)删除cookie
def logout(request):
rep = redirect("/login/")
rep.delete_cookie("user") # 删除用户浏览器上之前设置的user的cookie值
return rep
# cookie 版的登录校验
from django.shortcuts import render,redirect,HttpResponse
def login_required(func):
def inner(request,*args,**kwargs):
is_login = request.COOKIES.get(''is_login'')
#此时未登录前想要访问的页面
return_url = request.path_info
if is_login ==''1'':
ret = func(request,*args,**kwargs)
else:
#此时的标准地址,需要添加刚才想要访问的地址
ret= redirect(''/login/?return_url ={}''.format(return_url))
return ret
return inner
def login(request):
if request.method ==''POST'':
user = request.POST.get(''user'')
pwd = request.POST.get(''pwd'')
if user ==''alex'' and pwd == ''123'':
ret = redirect(''/home/'')
#response 对象
#set_cookie中有两个参数key &value 必填
ret.set_cookie(''is_login'',''1'')
return ret
else:
return render(request, ''login.html'')
return render(request,''login.html'')
#注;本质上是设置一个set_cookie的响应头,发请求时候是设置一个cookie的请求头
@login_required
def index(request):
return HttpResponse(''index'')
@login_required
def home(request):
# print(request.COOKIES,type(request.COOKIES))
# is_login = request.COOKIES.get(''is_login'')
# if is_login !=1:
# return redirect(''/login/'')
return HttpResponse(''home'')
2. session
2.1 session的概述
session的由来
- Cookie虽然在一定程度上解决了“保持状态”的需求,但是由于Cookie本身最大支持4096字节,以及Cookie本身保存在客户端,可能被拦截或窃取,因此就需要有一种新的东西,它能支持更多的字节,并且他保存在服务器,有较高的安全性。这就是Session。
- 问题来了,基于HTTP协议的无状态特征,服务器根本就不知道访问者是“谁”。那么上述的Cookie就起到桥接的作用。
- 我们可以给每个客户端的Cookie分配一个唯一的id,这样用户在访问时,通过Cookie,服务器就知道来的人是“谁”。然后我们再根据不同的Cookie的id,在服务器上保存一段时间的私密资料,如“账号密码”等等。
- 总结而言:Cookie弥补了HTTP无状态的不足,让服务器知道来的人是“谁”;但是Cookie以文本的形式保存在本地,自身安全性较差;所以我们就通过Cookie识别不同的用户,对应的在Session里保存私密的信息以及超过4096字节的文本。
- 另外,上述所说的Cookie和Session其实是共通性的东西,不限于语言和框架。
2.2 session的相关方法
# 获取、设置、删除Session中数据
request.session[''k1'']
request.session.get(''k1'',None)
request.session[''k1''] = 123
request.session.setdefault(''k1'',123) # 存在则不设置
del request.session[''k1'']
# 所有 键、值、键值对
request.session.keys()
request.session.values()
request.session.items()
request.session.iterkeys()
request.session.itervalues()
request.session.iteritems()
# 会话session的key
request.session.session_key
# 将所有Session失效日期小于当前日期的数据删除
request.session.clear_expired()
# 检查会话session的key在数据库中是否存在
request.session.exists("session_key")
# 删除当前会话的所有Session数据(删除服务器的session数据,不删除cookie)
request.session.delete()
# 删除当前的会话数据并删除会话的Cookie。(将session数据以及Cookie全部删除)
request.session.flush()
这用于确保前面的会话数据不可以再次被用户的浏览器访问
例如,django.contrib.auth.logout() 函数中就会调用它。
# 设置会话Session和Cookie的超时时间
request.session.set_expiry(value)
* 如果value是个整数,session会在些秒数后失效。
* 如果value是个datatime或timedelta,session就会在这个时间后失效。
* 如果value是0,用户关闭浏览器session就会失效。
* 如果value是None,session会依赖全局session失效策略。
2.3 session 的流程
2.4 session版登录验证
from functools import wraps
def check_login(func):
@wraps(func)
def inner(request, *args, **kwargs):
next_url = request.get_full_path()
if request.session.get("user"):
return func(request, *args, **kwargs)
else:
return redirect("/login/?next={}".format(next_url))
return inner
def login(request):
if request.method == "POST":
user = request.POST.get("user")
pwd = request.POST.get("pwd")
if user == "alex" and pwd == "alex1234":
# 设置session
request.session["user"] = user
# 获取跳到登陆页面之前的URL
next_url = request.GET.get("next")
# 如果有,就跳转回登陆之前的URL
if next_url:
return redirect(next_url)
# 否则默认跳转到index页面
else:
return redirect("/index/")
return render(request, "login.html")
@check_login
def logout(request):
# 删除所有当前请求相关的session
request.session.delete()
return redirect("/login/")
@check_login
def index(request):
current_user = request.session.get("user", None)
return render(request, "index.html", {"user": current_user})
Session版登录验证
2.5 Django中的Session配置


1. 数据库Session
SESSION_ENGINE = ''django.contrib.sessions.backends.db'' # 引擎(默认)
2. 缓存Session
SESSION_ENGINE = ''django.contrib.sessions.backends.cache'' # 引擎
SESSION_CACHE_ALIAS = ''default'' # 使用的缓存别名(默认内存缓存,也可以是memcache),此处别名依赖缓存的设置
3. 文件Session
SESSION_ENGINE = ''django.contrib.sessions.backends.file'' # 引擎
SESSION_FILE_PATH = None # 缓存文件路径,如果为None,则使用tempfile模块获取一个临时地址tempfile.gettempdir()
4. 缓存+数据库
SESSION_ENGINE = ''django.contrib.sessions.backends.cached_db'' # 引擎
5. 加密Cookie Session
SESSION_ENGINE = ''django.contrib.sessions.backends.signed_cookies'' # 引擎
其他公用设置项:
SESSION_COOKIE_NAME = "sessionid" # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串(默认)
SESSION_COOKIE_PATH = "/" # Session的cookie保存的路径(默认)
SESSION_COOKIE_DOMAIN = None # Session的cookie保存的域名(默认)
SESSION_COOKIE_SECURE = False # 是否Https传输cookie(默认)
SESSION_COOKIE_HTTPONLY = True # 是否Session的cookie只支持http传输(默认)
SESSION_COOKIE_AGE = 1209600 # Session的cookie失效日期(2周)(默认)
SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 是否关闭浏览器使得Session过期(默认)
SESSION_SAVE_EVERY_REQUEST = False # 是否每次请求都保存Session,默认修改之后才保存(默认)
Django - Cookie、Session、自定义分页和Django分页器


2. 今日内容
https://www.cnblogs.com/liwenzhou/p/8343243.html
1. Cookie和Session
1. Cookie
服务端:
1. 生成字符串
2. 随着响应将字符串回复给浏览器
3. 从浏览器发送的请求中拿到字符串
cookie就是保存在浏览器上的字符串!!!
每一次请求都会携带着cookie
把要保存的信息都保存在用户的浏览器上
好处:
服务端不用存,减轻了服务器压力
坏处:
信息不安全
Session:
搭配Cookie使用
Session本质上,保存在服务端的键值对。
好处:
用户的信息都保存在服务端,安全
坏处:
数据都保存在服务端,存储压力比较大
cookie和Session应用场景:
登录
刷票限制
保存用户的浏览习惯
Django中使用Session:
获取、设置、删除Session中数据
request.session[''k1'']
request.session.get(''k1'',None)
request.session[''k1''] = 123
request.session.setdefault(''k1'',123) # 存在则不设置
# 删除当前用户的所有Session数据
request.session.delete()
request.session.set_expiry(value)
* 如果value是个整数,session会在些秒数后失效。
* 如果value是个datatime或timedelta,session就会在这个时间后失效。
* 如果value是0,用户关闭浏览器session就会失效。
* 如果value是None,session会依赖全局session失效策略。
CBV加装饰器注意事项:
要将函数装饰器转成方法装饰器
from django.utils.decorators import method_decorator
@method_decorator(check_login)
2. 分页
第几页 数据 索引
1 1-10 0-10
2 11-20 10-20
3 21-30
----------------------------------------------


day 70 内容回顾
1.内容回顾
https://www.cnblogs.com/liwenzhou/p/8343243.html
1.cookie
本质上就是保存在浏览器上得键值对
为了解决HTTP请求是无状态得
可以用来做登录 7天免登录 浏览习惯 (每页显示多少条)
Django 操作Cookie
1.设置Cookie 是在response对象
1.明文的
rep = 响应对象(基础必备三件套)
rep.set_cookie(key,value,..)
2.加盐的
rep = 响应对象(基础必备三件套)
rep.set_signed_cookie(key,value,salt=''加密盐)
2.获取Cookie 是在request对象
1.明文的
request.COOKIES.get(''key'') / request.COOKIES[''key'']
2.加盐的
request.get_signed_cookie(key, default="默认值", salt='''', max_age=None)
2.session
1.定义
保存在服务器端的键值对,依赖与Cookie
2.Django的session 操作
1.设置session
request.session[''k1'']
request.session.setdefault(''k1'',123) # 存在则不设置
2.获取session
request.session.get(''k1'',None)
request.session[''k1'']
3.删除session
del request.session[''k1'']
注销之后删除用户所有的session数据
request.session.delete()
4.将所有Session失效日期小于当前日期的数据删除
request.session.clear_expired()
5.设置会话Session和Cookie的超时时间
request.session.set_expiry(value)
* 如果value是个整数,session会在些秒数后失效。
* 如果value是个datatime或timedelta,session就会在这个时间后失效。
* 如果value是0,用户关闭浏览器session就会失效。
* 如果value是None,session会依赖全局session失效策略。
3.FBV和CBV
CBV要加装饰器需要用到method_decorator
# 导入django 提供得工具 把函数装饰器变成方法装饰器
from django.utils.decorators import method_decorator
3.分页
1.自定义的分页
重在理解!
编程思想的建立是一个积累的过程。不要着急!!,知道怎么用
2.Djangon自带的分页
注意几个属性
一、Cookie
Cookie的由来
大家都知道HTTP协议是无状态的。
无状态的意思是每次请求都是独立的,它的执行情况和结果与前面的请求和之后的请求都无直接关系,它不会受前面的请求响应情况直接影响,也不会直接影响后面的请求响应情况。
状态可以理解为客户端和服务器在某次会话中产生的数据,那无状态的就以为这些数据不会被保留。会话中产生的数据又是我们需要保存的,也就是说要“保持状态”。因此Cookie就是在这样一个场景下诞生。
什么是Cookie
Cookie具体指的是一段小信息,它是服务器发送出来存储在浏览器上的一组组键值对,下次访问服务器时浏览器会自动携带这些键值对,以便服务器提取有用信息。
Cookie的原理
cookie的工作原理是:由服务器产生内容,浏览器收到请求后保存在本地;当浏览器再次访问时,浏览器会自动带上Cookie,这样服务器就能通过Cookie的内容来判断这个是“谁”了。
查看Cookie
我们使用Chrome浏览器,打开开发者工具。
Django中操作Cookie
获取Cookie
request.COOKIES[''key'']
request.get_signed_cookie(key, default=RAISE_ERROR, salt='''', max_age=None)
参数:
- default: 默认值
- salt: 加密盐
- max_age: 后台控制过期时间
设置Cookie
rep = HttpResponse(...)
rep = render(request, ...)
rep.set_cookie(key,value,...)
rep.set_signed_cookie(key,value,salt=''加密盐'',...)
参数:
- key, 键
- value='''', 值
- max_age=None, 超时时间
- expires=None, 超时时间(IE requires expires, so set it if hasn''t been already.)
- path=''/'', Cookie生效的路径,/ 表示根路径,特殊的:根路径的cookie可以被任何url的页面访问
- domain=None, Cookie生效的域名
- secure=False, https传输
- httponly=False 只能http协议传输,无法被JavaScript获取(不是绝对,底层抓包可以获取到也可以被覆盖)
删除Cookie
def logout(request):
rep = redirect("/login/")
rep.delete_cookie("user") # 删除用户浏览器上之前设置的usercookie值
return rep
Cookie版登陆校验
def check_login(func):
@wraps(func)
def inner(request, *args, **kwargs):
next_url = request.get_full_path()
if request.get_signed_cookie("login", salt="SSS", default=None) == "yes":
# 已经登录的用户...
return func(request, *args, **kwargs)
else:
# 没有登录的用户,跳转刚到登录页面
return redirect("/login/?next={}".format(next_url))
return inner
def login(request):
if request.method == "POST":
username = request.POST.get("username")
passwd = request.POST.get("password")
if username == "xxx" and passwd == "123":
next_url = request.GET.get("next")
if next_url and next_url != "/logout/":
response = redirect(next_url)
else:
response = redirect("/class_list/")
response.set_signed_cookie("login", "yes", salt="SSS")
return response
return render(request, "login.html")
二、Session
Session的由来
Cookie虽然在一定程度上解决了“保持状态”的需求,但是由于Cookie本身最大支持4096字节,以及Cookie本身保存在客户端,可能被拦截或窃取,因此就需要有一种新的东西,它能支持更多的字节,并且他保存在服务器,有较高的安全性。这就是Session。
问题来了,基于HTTP协议的无状态特征,服务器根本就不知道访问者是“谁”。那么上述的Cookie就起到桥接的作用。
我们可以给每个客户端的Cookie分配一个唯一的id,这样用户在访问时,通过Cookie,服务器就知道来的人是“谁”。然后我们再根据不同的Cookie的id,在服务器上保存一段时间的私密资料,如“账号密码”等等。
总结而言:Cookie弥补了HTTP无状态的不足,让服务器知道来的人是“谁”;但是Cookie以文本的形式保存在本地,自身安全性较差;所以我们就通过Cookie识别不同的用户,对应的在Session里保存私密的信息以及超过4096字节的文本。
另外,上述所说的Cookie和Session其实是共通性的东西,不限于语言和框架。
Django中Session相关方法
# 获取、设置、删除Session中数据
request.session[''k1'']
request.session.get(''k1'',None)
request.session[''k1''] = 123
request.session.setdefault(''k1'',123) # 存在则不设置
del request.session[''k1'']
# 所有 键、值、键值对
request.session.keys()
request.session.values()
request.session.items()
request.session.iterkeys()
request.session.itervalues()
request.session.iteritems()
# 会话session的key
request.session.session_key
# 将所有Session失效日期小于当前日期的数据删除
request.session.clear_expired()
# 检查会话session的key在数据库中是否存在
request.session.exists("session_key")
# 删除当前会话的所有Session数据
request.session.delete()
# 删除当前的会话数据并删除会话的Cookie。
request.session.flush()
这用于确保前面的会话数据不可以再次被用户的浏览器访问
例如,django.contrib.auth.logout() 函数中就会调用它。
# 设置会话Session和Cookie的超时时间
request.session.set_expiry(value)
* 如果value是个整数,session会在些秒数后失效。
* 如果value是个datatime或timedelta,session就会在这个时间后失效。
* 如果value是0,用户关闭浏览器session就会失效。
* 如果value是None,session会依赖全局session失效策略。
Session流程解析
Session版登陆验证
from functools import wraps
def check_login(func):
@wraps(func)
def inner(request, *args, **kwargs):
next_url = request.get_full_path()
if request.session.get("user"):
return func(request, *args, **kwargs)
else:
return redirect("/login/?next={}".format(next_url))
return inner
def login(request):
if request.method == "POST":
user = request.POST.get("user")
pwd = request.POST.get("pwd")
if user == "alex" and pwd == "alex1234":
# 设置session
request.session["user"] = user
# 获取跳到登陆页面之前的URL
next_url = request.GET.get("next")
# 如果有,就跳转回登陆之前的URL
if next_url:
return redirect(next_url)
# 否则默认跳转到index页面
else:
return redirect("/index/")
return render(request, "login.html")
@check_login
def logout(request):
# 删除所有当前请求相关的session
request.session.delete()
return redirect("/login/")
@check_login
def index(request):
current_user = request.session.get("user", None)
return render(request, "index.html", {"user": current_user})
Django中的Session配置
Django中默认支持Session,其内部提供了5种类型的Session供开发者使用。
1. 数据库Session
SESSION_ENGINE = ''django.contrib.sessions.backends.db'' # 引擎(默认)
2. 缓存Session
SESSION_ENGINE = ''django.contrib.sessions.backends.cache'' # 引擎
SESSION_CACHE_ALIAS = ''default'' # 使用的缓存别名(默认内存缓存,也可以是memcache),此处别名依赖缓存的设置
3. 文件Session
SESSION_ENGINE = ''django.contrib.sessions.backends.file'' # 引擎
SESSION_FILE_PATH = None # 缓存文件路径,如果为None,则使用tempfile模块获取一个临时地址tempfile.gettempdir()
4. 缓存+数据库
SESSION_ENGINE = ''django.contrib.sessions.backends.cached_db'' # 引擎
5. 加密Cookie Session
SESSION_ENGINE = ''django.contrib.sessions.backends.signed_cookies'' # 引擎
其他公用设置项:
SESSION_COOKIE_NAME = "sessionid" # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串(默认)
SESSION_COOKIE_PATH = "/" # Session的cookie保存的路径(默认)
SESSION_COOKIE_DOMAIN = None # Session的cookie保存的域名(默认)
SESSION_COOKIE_SECURE = False # 是否Https传输cookie(默认)
SESSION_COOKIE_HTTPONLY = True # 是否Session的cookie只支持http传输(默认)
SESSION_COOKIE_AGE = 1209600 # Session的cookie失效日期(2周)(默认)
SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 是否关闭浏览器使得Session过期(默认)
SESSION_SAVE_EVERY_REQUEST = False # 是否每次请求都保存Session,默认修改之后才保存(默认)
三、CBV加装饰器
CBV实现的登录视图
path(''book_list/'', views.BookList.as_view(),name=''book_list''),
from django.views import View
from django.utils.decorators import method_decorator
class LoginView(View):
def get(self, request):
"""
处理GET请求
"""
return render(request, ''login.html'')
def post(self, request):
"""
处理POST请求
"""
user = request.POST.get(''user'')
pwd = request.POST.get(''pwd'')
if user == ''alex'' and pwd == "alex1234":
next_url = request.GET.get("next")
# 生成随机字符串
# 写浏览器cookie -> session_id: 随机字符串
# 写到服务端session:
# {
# "随机字符串": {''user'':''alex''}
# }
request.session[''user''] = user
if next_url:
return redirect(next_url)
else:
return redirect(''/index/'')
return render(request, ''login.html'')
要在CBV视图中使用我们上面的check_login装饰器,有以下三种方式:
from django.utils.decorators import method_decorator
1. 加在CBV视图的get或post方法上
from django.utils.decorators import method_decorator
class HomeView(View):
def dispatch(self, request, *args, **kwargs):
return super(HomeView, self).dispatch(request, *args, **kwargs)
def get(self, request):
return render(request, "home.html")
@method_decorator(check_login)
def post(self, request):
print("Home View POST method...")
return redirect("/index/")
2. 加在dispatch方法上
from django.utils.decorators import method_decorator
class HomeView(View):
@method_decorator(check_login)
def dispatch(self, request, *args, **kwargs):
return super(HomeView, self).dispatch(request, *args, **kwargs)
def get(self, request):
return render(request, "home.html")
def post(self, request):
print("Home View POST method...")
return redirect("/index/")
因为CBV中首先执行的就是dispatch方法,所以这么写相当于给get和post方法都加上了登录校验。
3. 直接加在视图类上,但method_decorator必须传 name 关键字参数
如果get方法和post方法都需要登录校验的话就写两个装饰器。
from django.utils.decorators import method_decorator
@method_decorator(check_login, name="get")
@method_decorator(check_login, name="post")
class HomeView(View):
def dispatch(self, request, *args, **kwargs):
return super(HomeView, self).dispatch(request, *args, **kwargs)
def get(self, request):
return render(request, "home.html")
def post(self, request):
print("Home View POST method...")
return redirect("/index/")
补充
CSRF Token相关装饰器在CBV只能加到dispatch方法上
备注:
- csrf_protect,为当前函数强制设置防跨站请求伪造功能,即便settings中没有设置全局中间件。
- csrf_exempt,取消当前函数防跨站请求伪造功能,即便settings中设置了全局中间件。
from django.views.decorators.csrf import csrf_exempt, csrf_protect
class HomeView(View):
@method_decorator(csrf_exempt)
def dispatch(self, request, *args, **kwargs):
return super(HomeView, self).dispatch(request, *args, **kwargs)
def get(self, request):
return render(request, "home.html")
def post(self, request):
print("Home View POST method...")
return redirect("/index/")
四、分页
1.自定义分页
data = []
for i in range(1, 302):
tmp = {"id": i, "name": "alex-{}".format(i)}
data.append(tmp)
print(data)
def user_list(request):
# user_list = data[0:10]
# user_list = data[10:20]
try:
current_page = int(request.GET.get("page"))
except Exception as e:
current_page = 1
per_page = 10
# 数据总条数
total_count = len(data)
# 总页码
total_page, more = divmod(total_count, per_page)
if more:
total_page += 1
# 页面最多显示多少个页码
max_show = 11
half_show = int((max_show-1)/2)
if current_page <= half_show:
show_start = 1
show_end = max_show
else:
if current_page + half_show >= total_page:
show_start = total_page - max_show
show_end = total_page
else:
show_start = current_page - half_show
show_end = current_page + half_show
# 数据库中获取数据
data_start = (current_page - 1) * per_page
data_end = current_page * per_page
user_list = data[data_start:data_end]
# 生成页面上显示的页码
page_html_list = []
# 加首页
first_li = ''<li><a href="/user_list/?page=1">首页</a></li>''
page_html_list.append(first_li)
# 加上一页
if current_page == 1:
prev_li = ''<li><a href="#">上一页</a></li>''
else:
prev_li = ''<li><a href="/user_list/?page={}">上一页</a></li>''.format(current_page - 1)
page_html_list.append(prev_li)
for i in range(show_start, show_end+1):
if i == current_page:
li_tag = ''<li><a href="/user_list/?page={0}">{0}</a></li>''.format(i)
else:
li_tag = ''<li><a href="/user_list/?page={0}">{0}</a></li>''.format(i)
page_html_list.append(li_tag)
# 加下一页
if current_page == total_page:
next_li = ''<li><a href="#">下一页</a></li>''
else:
next_li = ''<li><a href="/user_list/?page={}">下一页</a></li>''.format(current_page+1)
page_html_list.append(next_li)
# 加尾页
page_end_li = ''<li><a href="/user_list/?page={}">尾页</a></li>''.format(total_page)
page_html_list.append(page_end_li)
page_html = "".join(page_html_list)
return render(request, "user_list.html", {"user_list": user_list, "page_html": page_html})
class Pagination(object):
def __init__(self, current_page, total_count, base_url, per_page=10, max_show=11):
"""
:param current_page: 当前页
:param total_count: 数据库中数据总数
:param per_page: 每页显示多少条数据
:param max_show: 最多显示多少页
"""
try:
current_page = int(current_page)
except Exception as e:
current_page = 1
self.current_page = current_page
self.total_count = total_count
self.base_url = base_url
self.per_page = per_page
self.max_show = max_show
# 总页码
total_page, more = divmod(total_count, per_page)
if more:
total_page += 1
half_show = int((max_show - 1) / 2)
self.half_show = half_show
self.total_page = total_page
@property
def start(self):
return (self.current_page - 1) * self.per_page
@property
def end(self):
return self.current_page * self.per_page
def page_html(self):
if self.current_page <= self.half_show:
show_start = 1
show_end = self.max_show
else:
if self.current_page + self.half_show >= self.total_page:
show_start = self.total_page - self.max_show
show_end = self.total_page
else:
show_start = self.current_page - self.half_show
show_end = self.current_page + self.half_show
# 生成页面上显示的页码
page_html_list = []
# 加首页
first_li = ''<li><a href="{}?page=1">首页</a></li>''.format(self.base_url)
page_html_list.append(first_li)
# 加上一页
if self.current_page == 1:
prev_li = ''<li><a href="#">上一页</a></li>''
else:
prev_li = ''<li><a href="{0}?page={1}">上一页</a></li>''.format(self.base_url, self.current_page - 1)
page_html_list.append(prev_li)
for i in range(show_start, show_end + 1):
if i == self.current_page:
li_tag = ''<li><a href="{0}?page={1}">{1}</a></li>''.format(self.base_url, i)
else:
li_tag = ''<li><a href="{0}?page={1}">{1}</a></li>''.format(self.base_url, i)
page_html_list.append(li_tag)
# 加下一页
if self.current_page == self.total_page:
next_li = ''<li><a href="#">下一页</a></li>''
else:
next_li = ''<li><a href="{0}?page={1}">下一页</a></li>''.format(self.base_url, self.current_page + 1)
page_html_list.append(next_li)
# 加尾页
page_end_li = ''<li><a href="{0}?page={1}">尾页</a></li>''.format(self.base_url, self.total_page)
page_html_list.append(page_end_li)
return "".join(page_html_list)
def user_list(request):
pager = Pagination(request.GET.get("page"), len(data), request.path_info)
user_list = data[pager.start:pager.end]
page_html = pager.page_html()
return render(request, "user_list.html", {"user_list": user_list, "page_html": page_html})
2.Django内置分页
from django.shortcuts import render
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
L = []
for i in range(999):
L.append(i)
def index(request):
current_page = request.GET.get(''p'')
paginator = Paginator(L, 10)
# per_page: 每页显示条目数量
# count: 数据总个数
# num_pages:总页数
# page_range:总页数的索引范围,如: (1,10),(1,200)
# page: page对象
try:
posts = paginator.page(current_page)
# has_next 是否有下一页
# next_page_number 下一页页码
# has_previous 是否有上一页
# previous_page_number 上一页页码
# object_list 分页之后的数据列表
# number 当前页
# paginator paginator对象
except PageNotAnInteger:
posts = paginator.page(1)
except EmptyPage:
posts = paginator.page(paginator.num_pages)
return render(request, ''index.html'', {''posts'': posts})
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body>
<ul>
{% for item in posts %}
<li>{{ item }}</li>
{% endfor %}
</ul>
<div class="pagination">
<span class="step-links">
{% if posts.has_previous %}
<a href="?p={{ posts.previous_page_number }}">Previous</a>
{% endif %}
<span class="current">
Page {{ posts.number }} of {{ posts.paginator.num_pages }}.
</span>
{% if posts.has_next %}
<a href="?p={{ posts.next_page_number }}">Next</a>
{% endif %}
</span>
</div>
</body>
</html>
五、示例
BMS settings.py


"""
Django settings for BMS project.
Generated by ''django-admin startproject'' using Django 2.0.1.
For more information on this file, see
https://docs.djangoproject.com/en/2.0/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/2.0/ref/settings/
"""
import os
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/2.0/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = ''nk!!3wd)(-d!@0(^3+xr_2+1xucs01mj5m$lw%t0z@^c*@_#an''
# SECURITY WARNING: don''t run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = [
''django.contrib.admin'',
''django.contrib.auth'',
''django.contrib.contenttypes'',
''django.contrib.sessions'',
''django.contrib.messages'',
''django.contrib.staticfiles'',
''app01.apps.App01Config'',
]
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'',
]
ROOT_URLCONF = ''BMS.urls''
TEMPLATES = [
{
''BACKEND'': ''django.template.backends.django.DjangoTemplates'',
''DIRS'': [os.path.join(BASE_DIR, ''templates'')]
,
''APP_DIRS'': True,
''OPTIONS'': {
''context_processors'': [
''django.template.context_processors.debug'',
''django.template.context_processors.request'',
''django.contrib.auth.context_processors.auth'',
''django.contrib.messages.context_processors.messages'',
],
},
},
]
WSGI_APPLICATION = ''BMS.wsgi.application''
# Database
# https://docs.djangoproject.com/en/2.0/ref/settings/#databases
# DATABASES = {
# ''default'': {
# ''ENGINE'': ''django.db.backends.sqlite3'',
# ''NAME'': os.path.join(BASE_DIR, ''db.sqlite3''),
# }
# }
DATABASES = {
''default'': {
''ENGINE'': ''django.db.backends.mysql'',
''NAME'': ''bms69'',
''HOST'':''127.0.0.1'',
''PORT'':3306,
''USER'':''root'',
''PASSWORD'':''123'',
}
}
# Password validation
# https://docs.djangoproject.com/en/2.0/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
''NAME'': ''django.contrib.auth.password_validation.UserAttributeSimilarityValidator'',
},
{
''NAME'': ''django.contrib.auth.password_validation.MinimumLengthValidator'',
},
{
''NAME'': ''django.contrib.auth.password_validation.CommonPasswordValidator'',
},
{
''NAME'': ''django.contrib.auth.password_validation.NumericPasswordValidator'',
},
]
# Internationalization
# https://docs.djangoproject.com/en/2.0/topics/i18n/
LANGUAGE_CODE = ''en-us''
TIME_ZONE = ''UTC''
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/2.0/howto/static-files/
STATIC_URL = ''/static/''
STATICFILES_DIRS = [
os.path.join(BASE_DIR,''static'')
]
LOGGING = {
''version'': 1,
''disable_existing_loggers'': False,
''handlers'': {
''console'':{
''level'':''DEBUG'',
''class'':''logging.StreamHandler'',
},
},
''loggers'': {
''django.db.backends'': {
''handlers'': [''console''],
''propagate'': True,
''level'':''DEBUG'',
},
}
}
BMS urls.py


"""BMS URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/2.0/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('''', views.home, name=''home'')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('''', Home.as_view(), name=''home'')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path(''blog/'', include(''blog.urls''))
"""
from django.contrib import admin
from django.urls import path,re_path
from app01 import views
urlpatterns = [
re_path(r"^login/",views.login,name=''login''),
re_path(r"^logout/",views.logout,name=''logout''),
re_path(r''^publisher_list/'',views.publisher_list,name=''publisher_list''),
re_path(r''^delete_publisher/'',views.delete_publisher,name=''delete_publisher''),
re_path(r''^home/'',views.home,name="home"),
# re_path(r''^book_list/'',views.book_list,name="book_list"),
re_path(r''^book_list/'',views.BookList.as_view(),name="book_list"),
# 类视图 要调用as_view()
# 以ip和端口后面什么都没有,就能匹配上url
re_path(r''^$'',views.publisher_list),
]
BMS __init__.py


import pymysql
pymysql.install_as_MySQLdb()
app01 models.py


from django.db import models
# 出版社类
class Publisher(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=32)
def __str__(self):
return self.name
# 书类
class Book(models.Model):
id = models.AutoField(primary_key=True)
title = models.CharField(max_length=32)
# 书的价格
price = models.DecimalField(max_digits=8, decimal_places=2) # 999999.99
# 出版日期
publish_date = models.DateTimeField(auto_now=True) # datetime.date()
# 书只能关联一个出版社, 外键通常建在多的那一边
publisher = models.ForeignKey(to="Publisher", on_delete=models.CASCADE)
def __str__(self):
return self.title
# 作者类
class Author(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=16)
# 多对多, 建在哪边都可以
books = models.ManyToManyField(to="Book", related_name="authors") # 多对多关联
detail = models.OneToOneField(to="AuthorDetail", null=True,on_delete=models.CASCADE) # 作者详情数据的id在这张表是唯一的
def __str__(self):
return self.name
# 作者详情
class AuthorDetail(models.Model):
age = models.IntegerField()
addr = models.TextField()
# python manage.py makemigrations
# python manage.py migrate
#
# 在项目的bms __init__ 下设置
# import pymysql
# pymysql.install_as_MySQLdb()
app01 views.py


from django.shortcuts import render,redirect,HttpResponse
from django.urls import reverse
from app01.models import *
# 判断用户有没有登录得装饰器 ,
def check_login(func):
def inner(request,*args,**kwargs):
# 把当前访问得网址拿到
url = request.get_full_path()
# login_user = request.COOKIES.get(''login'', None)
# login_user = request.get_signed_cookie(''login'',default=None,salt=''hehe'')
login_status = request.session.get(''login'')
login_user = request.session.get(''user'')
if login_status == ''1'': # 登录成功
print(''验证通过''.center(120,''*''))
return func(request,*args,**kwargs) # 执行被装饰得函数
else:
print(''验证失败''.center(120, ''*''))
return redirect(''/login/?next={}''.format(url))
return inner
# 登录
# def login(request):
# # /login/?next=/book_list/
# # /login/?next=/publisher_list/
# if request.method == ''POST'':
# next_url = request.GET.get(''next'')
#
# username = request.POST.get(''user'')
# password = request.POST.get(''pwd'')
#
# if username == ''alex'' and password == ''123'':
# # 登录成功,跳转到首页
# # 给用户生成一个字符串,让它保存在里游览器上(这个字符串就是Cookie)
# rep = redirect(next_url)
# # 生成字符串 并且随着响应返回给浏览器
#
# # rep.set_cookie("login",''alex'')
# rep.set_signed_cookie("login",''alex'',salt=''hehe'',max_age = 7)
# # 7s 之后失效 加密过得cookie
#
# print(''===='',rep)
# # <HttpResponseRedirect status_code=302, "text/html; charset=utf-8", url="/home/">
# return rep
#
# return render(request,''login.html'')
# session版登录
def login(request):
if request.method == ''POST'':
next_url = request.GET.get(''next'')
username = request.POST.get(''user'')
password = request.POST.get(''pwd'')
if username == ''alex'' and password == ''123'':
# 利用session 保存一个login=alex
request.session[''user''] = ''alex''
request.session[''login''] = ''1''
request.session.set_expiry(86400)
# 7s 之后失效 设置浏览器失效时间
rep = redirect(next_url)
return rep
return render(request,''login.html'')
def logout(request):
# 把当前用户得session 都清掉
request.session.delete()
return redirect(''/login'')
# 首页
def home(request):
return render(request,''home.html'')
# 出版社列表
@check_login
def publisher_list(request):
# # 判断用户有没有 登录
# # 实际上就是判断请求得cookie中有没有login 1
# print(request.COOKIES)
# # {''csrftoken'': ''NtrDhwNbXcnTSqmxa7wITT1UqccZYu2Z8ywHdf2rYhyURwdtaOAf702tsLkVfqD7'', ''login'': ''1''}
#
#
# if login_user == ''alex'': # 登录成功
# publisher_list = Publisher.objects.all()
# return render(request,''publisher_list.html'',{''publisher_list'':publisher_list,''user'':login_user})
# else:
# return redirect(reverse(''login''))
# 查询出所有数据
# data = Publisher.objects.all()
# # 这里斌不会查询数据库,在对data 操作时,才会查询数据库 data[3:10]
# # 总共需要多少页
# # 每页显示10条
# per_page = 10
# data_num = data.count() # 数据得总数
# # page_num,more = divmod(data_num,per_page)
# # if more:
# # page_num += 1
# current_page = request.GET.get(''page'',1)
#
# # try:
# # current_page = int(current_page)
# # except Exception as e:
# # current_page = 1
# # if current_page <= 0: # 如果页面数是 负数
# # current_page = 1
# # elif current_page > page_num: # 如果页面 大于 总页面
# # current_page = page_num
#
# # 页面最多显示11个页面 , 当前页数 左 + 5 右 + 5
# max_show = 7
# # half_show = max_show//2
# # # 页面最左边显示多少
# # if current_page - half_show <= 1:
# # page_start = 1
# # page_end = max_show
# # elif current_page + half_show >= page_num: # 如果右边 越界了
# # page_start = page_num - max_show + 1
# # page_end = page_num
# # else:
# # page_start = current_page - half_show
# # page_end = current_page + half_show
# from utils import mypage
# obj = mypage.Pagination(data_num,current_page)
# 当前页是第3页 (3-1)*10 - 3*10
# date_start = (current_page-1) * per_page # 数据从哪开始切
# data_end = current_page * per_page # 数据切到哪
# publisher_list = Publisher.objects.all()
# publisher_list = Publisher.objects.all()[20:30]
# publisher_list = data[obj.start:obj.end]
# # 生成页码
# li = []
# # 加一个首页
# li.append(''<li><a href="/publisher_list/?page=1">首页</a></li>'')
# # 加一个上一页
# if current_page == 1:
# li.append(''<li><a href="/publisher_list/?page={0}"><span aria-hidden="true">«</span></a></li>''.format(
# current_page))
# else:
# li.append(''<li><a href="/publisher_list/?page={0}"><span aria-hidden="true">«</span></a></li>''.format(
# current_page - 1))
# for i in range(page_start,page_end+1):
# if i == current_page:
# tmp = ''<li><a href="/publisher_list/?page={0}">{0}</a></li>''.format(i)
# else:
# tmp = ''<li><a href="/publisher_list/?page={0}">{0}</a></li>''.format(i)
# li.append(tmp)
# # 加一个下一页
# if current_page == page_num:
# li.append(''<li><a href="/publisher_list/?page={0}"><span aria-hidden="true">»</span></a></li>''.format(
# current_page))
# else:
# li.append(''<li><a href="/publisher_list/?page={0}"><span aria-hidden="true">»</span></a></li>''.format(
# current_page + 1))
# li.append(''<li><a href="/publisher_list/?page={0}">尾页</a></li>''.format(page_num))
# page_html = "".join(li)
data = Publisher.objects.all()
data_num = data.count() # 数据得总数
current_page = request.GET.get(''page'', 1)
from utils import mypage
obj = mypage.Pagination(data_num,current_page,request.path)
publisher_list = data[obj.start:obj.end]
page_html = obj.page_html()
return render(
request,
''publisher_list.html'',
{''publisher_list'': publisher_list,''page_html'':page_html}
)
# # 书籍列表页
# @check_login
# def book_list(request):
# return render(request,''book_list.html'')
# FBV(function base views) 就是在视图里使用函数处理请求。
# CBV版书籍列表
# CBV(class base views)就是在视图里使用类处理请求。
from django.views import View
# 导入django 提供得工具 把函数装饰器变成方法装饰器
from django.utils.decorators import method_decorator
''''''三个地方可加装饰器''''''
#
# # @method_decorator(check_login,name=''get'')
# class BookList(View):
# # @method_decorator(check_login)
# # def dispatch(self, request, *args, **kwargs):
# # super(BookList, self).dispatch(request,*args,**kwargs)
#
# @method_decorator(check_login)
# def get(self,request):
# current_page = request.GET.get(''page'',1)
# data = Book.objects.all()
# from utils import mypage
# obj = mypage.Pagination(data.count(),current_page,request.path)
#
# book_list = data[obj.start:obj.end]
# page_html = obj.page_html()
# return render(request,''book_list.html'',{''book_list'':book_list,''page_html'':page_html})
#
# 使用django 内置得分页
from django.core.paginator import Paginator,EmptyPage,PageNotAnInteger
class BookList(View):
@method_decorator(check_login)
def get(self,request):
current_page = request.GET.get(''page'',1)
data = Book.objects.all()
# 用内置得分页类 得到一个分页对象
page_obj = Paginator(data,10)
try:
# 尝试去取 current_page
ret = page_obj.page(current_page)
except PageNotAnInteger:
ret = page_obj.page(1) # 返回第一页
except EmptyPage:
ret = page_obj.page(page_obj.num_pages) # 返回最后一页
return render(request,''book_list2.html'',{''book_list'':ret,})
def delete_publisher(request):
delete_id = request.POST.get(''publisher_id'')
try:
Publisher.objects.filter(id = delete_id).delete()
ret = {''status'':0}
except Exception as e:
ret = {''status'':1,"msg":''删除失败''}
import json
json_ret = json.dumps(ret)
return HttpResponse(json_ret)
app01 tests.py


from django.test import TestCase
from functools import wraps
#
# def my_decorator(func):
# def wrapper(*args, **kwargs):
# ''''''''''decorator''''''
# print(''Calling decorated function...'')
# return func(*args, **kwargs)
#
# return wrapper
#
# @my_decorator
# def example():
# """Docstring"""
# print(''Called example function'')
#
#
# print(example.__name__, example.__doc__)
# # wrapper ''''decorator
# coding=utf-8
# -*- coding=utf-8 -*-
# from functools import wraps
#
#
# def my_decorator(func):
# @wraps(func)
# def wrapper(*args, **kwargs):
# ''''''''''decorator''''''
# print(''Calling decorated function...'')
# return func(*args, **kwargs)
#
# return wrapper
#
#
# @my_decorator
# def example():
# """Docstring"""
# print(''Called example function'')
#
#
# print(example.__name__, example.__doc__)
# example Docstring
templates book_list.html


<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>book_list</title>
<link rel="stylesheet" href="/static/bootstrap-3.3.7/css/bootstrap.min.css">
</head>
<body>
<h1>这是书籍列表页</h1>
<a href="/logout">注销</a>
<div class="container">
<table class="table table-bordered">
<thead>
<tr>
<th>#</th>
<th>ID</th>
<th>书籍名称</th>
</tr>
</thead>
<tbody>
{% for book in book_list %}
<tr>
<td>{{ forloop.counter }}</td>
<td>{{ book.id }}</td>
<td>{{ book.title }}</td>
</tr>
{% endfor %}
</tbody>
</table>
<nav aria-label="...">
<ul class="pagination">
{{ page_html|safe }}
</ul>
</nav>
</div>
<script src="/static/jquery-3.2.1.min.js"></script>
<script src="/static/bootstrap-3.3.7/js/bootstrap.min.js"></script>
</body>
</html>
templates book_list2.html


<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>book_list</title>
<link rel="stylesheet" href="/static/bootstrap-3.3.7/css/bootstrap.min.css">
</head>
<body>
<h1>这是书籍列表页</h1>
<a href="/logout">注销</a>
<div class="container">
<table class="table table-bordered">
<thead>
<tr>
<th>#</th>
<th>ID</th>
<th>书籍名称</th>
</tr>
</thead>
<tbody>
{% for book in book_list %}
<tr>
<td>{{ forloop.counter }}</td>
<td>{{ book.id }}</td>
<td>{{ book.title }}</td>
</tr>
{% endfor %}
</tbody>
</table>
<nav aria-label="...">
<ul class="pagination">
{% if book_list.has_previous %}
<li><a href="/book_list?page={{ book_list.previous_page_number }}">«</a></li>
{% else %}
<li class="disabled"><a href="#">«</a></li>
{% endif %}
<li class="active"><a href="/book_list?page={{ book_list.number }}">{{ book_list.number }}</a></li>
{% if book_list.has_next %}
<li><a href="/book_list?page={{ book_list.next_page_number}}">»</a></li>
{% else %}
<li class="disabled"><a href="#">»</a></li>
{% endif %}
</ul>
</nav>
</div>
<script src="/static/jquery-3.2.1.min.js"></script>
<script src="/static/bootstrap-3.3.7/js/bootstrap.min.js"></script>
</body>
</html>
templates home.html


<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>home</title>
</head>
<body>
<h1>这是home页面!!!</h1>
</body>
</html>
templates login.html


<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>login</title>
</head>
<body>
{# action 为空 表示往当前url 提交 #}
{#<form action="" method="post">#}
<form action="{{ request.get_full_path }}" method="post">
{% csrf_token %}
<input type="text" name="user">
<input type="password" name="pwd">
<input type="submit" value="登录">
</form>
</body>
</html>
templates publisher_list.html


<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>publisher_list</title>
<link rel="stylesheet" href="/static/bootstrap-3.3.7/css/bootstrap.min.css">
<link rel="stylesheet" href="/static/plugins/sweetalert/sweetalert.css">
<style type="text/css">
.sweet-alert h2{padding-top: 20px;}
</style>
</head>
<body>
<a href="/logout">注销</a>
<div class="container">
<table class="table table-bordered">
<thead>
<tr>
<th>#</th>
<th>ID</th>
<th>出版社名称</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for publisher in publisher_list %}
<tr>
<td>{{ forloop.counter }}</td>
<td>{{ publisher.id }}</td>
<td>{{ publisher.name }}</td>
<td>
{# https://github.com/lipis/bootstrap-sweetalert #}
<button class="btn btn-danger delete">删除</button>
</td>
</tr>
{% endfor %}
</tbody>
</table>
<nav aria-label="...">
<ul class="pagination">
{{ page_html|safe }}
</ul>
</nav>
</div>
<script src="/static/jquery-3.2.1.min.js"></script>
<script src="/static/init_ajax.js"></script>
<script src="/static/bootstrap-3.3.7/js/bootstrap.min.js"></script>
<script src="/static/plugins/sweetalert/sweetalert.min.js"></script>
<script type="text/javascript">
//给删除按钮绑定事件
$(''.delete'').click(function () {
var id = $(this).parent().prev().prev().text();
var $currentTr = $(this).parent().parent();
swal({
title: "确定要删除吗? ",
text: "删了就找不回来了",
type: "warning",
showCancelButton: true, // 显不显示取消按钮
confirmButtonClass: "btn-danger",
confirmButtonText: "是,就是删除", //取消按钮上的文字
closeOnConfirm: false
},
function(){
$.ajax({
url:''/delete_publisher/'',
type:''post'',
data:{''publisher_id'':id},
success:function (arg) {
var ret = JSON.parse(arg);
if(ret.status === 0){
$currentTr.remove();
swal("删除成功!", "你可以跑路了", "success");
}else{
swal(ret.msg, "你可以尝试在删一次", "error");
}
}
});
});
});
</script>
</body>
</html>
{# 下载 dist css js 引入 #}
{# https://github.com/lipis/bootstrap-sweetalert #}
{# https://lipis.github.io/bootstrap-sweetalert/ #}
utils mypage.py


''''''
自定义分页组件
''''''
class Pagination(object):
def __init__(self, data_num, current_page,url_prefix, per_page = 10, max_show = 11):
"""
进行初始化
:param data_num: 数据总数
:param current_page: 当前页
:param url_prefix: 生成得页码得链接前缀
:param per_page: 每页显示多少条数据
:param max_show: 页面最多显示多少个页码
"""
self.data_num = data_num
self.per_page = per_page
self.max_show = max_show
self.url_prefix = url_prefix
# 把页码数算出来
self.page_num, more = divmod(self.data_num, self.per_page)
if more:
self.page_num += 1
try:
current_page = int(current_page)
except Exception as e:
current_page = 1
if current_page <= 0: # 如果页面数是 负数
current_page = 1
elif current_page > self.page_num: # 如果页面 大于 总页面
current_page = self.page_num
self.current_page = current_page
# 页码数得一半
self.half_show = self.max_show // 2
if self.current_page - self.half_show <= 1:
self.page_start = 1
self.page_end = self.max_show
elif self.current_page + self.half_show >= self.page_num: # 如果右边 越界了
self.page_start = self.page_num - self.max_show + 1
self.page_end = self.page_num
else:
self.page_start = self.current_page - self.half_show
self.page_end = self.current_page + self.half_show
@property
def start(self):
return (self.current_page-1) * self.per_page # 数据从哪开始切
@property
def end(self):
return self.current_page * self.per_page # 数据切到哪
def page_html(self):
# 生成页码
li = []
# 加一个首页
li.append(''<li><a href="{}?page=1">首页</a></li>''.format(self.url_prefix))
# 加一个上一页
if self.current_page == 1:
li.append(
''<li><a href="#"><span aria-hidden="true">«</span></a></li>'')
else:
li.append(''<li><a href="{0}?page={1}"><span aria-hidden="true">«</span></a></li>''.format(
self.url_prefix,self.current_page - 1))
for i in range(self.page_start, self.page_end + 1):
if i == self.current_page:
tmp = ''<li><a href="{0}?page={1}">{1}</a></li>''.format(self.url_prefix,i)
else:
tmp = ''<li><a href="{0}?page={1}">{1}</a></li>''.format(self.url_prefix,i)
li.append(tmp)
# 加一个下一页
if self.current_page == self.page_num:
li.append(
''<li><a href="#"><span aria-hidden="true">»</span></a></li>'')
else:
li.append(''<li><a href="{0}?page={1}"><span aria-hidden="true">»</span></a></li>''.format(self.url_prefix,
self.current_page + 1))
li.append(''<li><a href="{0}?page={1}">尾页</a></li>''.format(self.url_prefix,self.page_num))
return "".join(li)
myscript.py


# -*- coding:utf-8 -*-
import os
if __name__ == ''__main__'':
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "BMS.settings")
import django
django.setup()
# 创建300个出版社
from app01 import models
# Publisher.objects.create(name=''水星第{}出版社''.format(i))
# obj = Publisher(name=''火星出版社'')
# obj.save()
# ret = []
# for i in range(300):
# obj = Publisher(name=''水星第{}出版社''.format(i))
# ret.append(obj)
# ret = [models.Publisher(name=''水星第{}出版社''.format(i)) for i in range(300)]
# 批量创建300个出版社对象
# models.Publisher.objects.bulk_create(ret) # 只提交一次
# 创建300本书
import random
ret = [models.Book(title=''番茄物语{}''.format(i),price=random.randint(10, 90),publisher_id=1) for i in range(300)]
models.Book.objects.bulk_create(ret)
https://github.com/alice-bj/BMS
六、线上 - Django分页器
view
from django.shortcuts import render,HttpResponse
# Create your views here.
from app01.models import *
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
def index(request):
''''''
批量导入数据:
Booklist=[]
for i in range(100):
Booklist.append(Book(title="book"+str(i),price=30+i*i))
Book.objects.bulk_create(Booklist)
''''''
''''''
分页器的使用:
book_list=Book.objects.all()
paginator = Paginator(book_list, 10)
print("count:",paginator.count) #数据总数
print("num_pages",paginator.num_pages) #总页数
print("page_range",paginator.page_range) #页码的列表
page1=paginator.page(1) #第1页的page对象
for i in page1: #遍历第1页的所有数据对象
print(i)
print(page1.object_list) #第1页的所有数据
page2=paginator.page(2)
print(page2.has_next()) #是否有下一页
print(page2.next_page_number()) #下一页的页码
print(page2.has_previous()) #是否有上一页
print(page2.previous_page_number()) #上一页的页码
# 抛错
#page=paginator.page(12) # error:EmptyPage
#page=paginator.page("z") # error:PageNotAnInteger
''''''
book_list=Book.objects.all()
paginator = Paginator(book_list, 10)
page = request.GET.get(''page'',1)
currentPage=int(page)
try:
print(page)
book_list = paginator.page(page)
except PageNotAnInteger:
book_list = paginator.page(1)
except EmptyPage:
book_list = paginator.page(paginator.num_pages)
return render(request,"index.html",{"book_list":book_list,"paginator":paginator,"currentPage":currentPage})
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"
integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
</head>
<body>
<div class="container">
<h4>分页器</h4>
<ul>
{% for book in book_list %}
<li>{{ book.title }} -----{{ book.price }}</li>
{% endfor %}
</ul>
<ul class="pagination" id="pager">
{% if book_list.has_previous %}
<li class="previous"><a href="/index/?page={{ book_list.previous_page_number }}">上一页</a></li>
{% else %}
<li class="previous disabled"><a href="#">上一页</a></li>
{% endif %}
{% for num in paginator.page_range %}
{% if num == currentPage %}
<li class="item active"><a href="/index/?page={{ num }}">{{ num }}</a></li>
{% else %}
<li class="item"><a href="/index/?page={{ num }}">{{ num }}</a></li>
{% endif %}
{% endfor %}
{% if book_list.has_next %}
<li class="next"><a href="/index/?page={{ book_list.next_page_number }}">下一页</a></li>
{% else %}
<li class="next disabled"><a href="#">下一页</a></li>
{% endif %}
</ul>
</div>
</body>
</html>


def index(request):
book_list=Book.objects.all()
paginator = Paginator(book_list, 15)
page = request.GET.get(''page'',1)
currentPage=int(page)
# 如果页数十分多时,换另外一种显示方式
if paginator.num_pages>11:
if currentPage-5<1:
pageRange=range(1,11)
elif currentPage+5>paginator.num_pages:
pageRange=range(currentPage-5,paginator.num_pages+1)
else:
pageRange=range(currentPage-5,currentPage+5)
else:
pageRange=paginator.page_range
try:
print(page)
book_list = paginator.page(page)
except PageNotAnInteger:
book_list = paginator.page(1)
except EmptyPage:
book_list = paginator.page(paginator.num_pages)
return render(request,"index.html",locals())
示例:
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>index</title>
<link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
</head>
<body>
<ul>
{% for book in current_page %}
<li>{{ book.title }} - {{ book.price }}</li>
{% endfor %}
</ul>
<nav aria-label="Page navigation">
<ul class="pagination">
<li><a href="?page=1">首页</a></li>
{% if current_page.has_previous %}
<li>
<a href="?page={{ current_page.previous_page_number }}" aria-label="Previous">
<span aria-hidden="true">上一页</span>
</a>
</li>
{% else %}
<li class="disabled">
<a href="" aria-label="Previous">
<span aria-hidden="true">上一页</span>
</a>
</li>
{% endif %}
{% for item in page_range %}
{% if current_page_num == item %}
<li class="active"><a href="?page={{ item }}">{{ item }}</a></li>
{% else %}
<li><a href="?page={{ item }}">{{ item }}</a></li>
{% endif %}
{% endfor %}
{% if current_page.has_next %}
<li>
<a href="?page={{ current_page.next_page_number }}" aria-label="Next">
<span aria-hidden="true">下一页</span>
</a>
</li>
{% else %}
<li class="disabled">
<a href="" aria-label="Next">
<span aria-hidden="true">下一页</span>
</a>
</li>
{% endif %}
<li><a href="?page={{ paginator.num_pages }}">尾页</a></li>
</ul>
</nav>
</body>
</html>
views.py
from django.shortcuts import render,HttpResponse
# Create your views here.
from django.core.paginator import Paginator,EmptyPage,PageNotAnInteger
from app01.models import Book
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)
''''''
book_list = Book.objects.all()
paginator = Paginator(book_list,6) # 20显示20个数据
print(paginator.count) # 数据总数 100
print(paginator.num_pages) # 总页数 13
print(paginator.page_range) # 页码的列表 range(1,14)
current_page_num = int(request.GET.get(''page'', 1))
show_page = 7
half_show_page = int(show_page/2)
if paginator.num_pages > show_page: # 11 表示显示11个页码
if current_page_num - half_show_page < 1:
page_range = range(1,show_page+1)
elif current_page_num + half_show_page > paginator.num_pages:
page_range = range(paginator.num_pages-show_page+1,paginator.num_pages+1)
else:
page_range = range(current_page_num-half_show_page,current_page_num+half_show_page+1)
else:
page_range = paginator.page_range
try:
# 显示某一页具体数据
current_page = paginator.page(current_page_num)
print(current_page.object_list)
for i in current_page:
print(i)
except EmptyPage as e:
current_page = paginator.page(paginator.num_pages)
except PageNotAnInteger as e:
current_page = paginator.page(1)
return render(request,''index.html'',locals())
''''''
http://www.cnblogs.com/yuanchenqi/articles/9036515.html
批量插入
Booklist=[]
for i in range(100):
Booklist.append(Book(title="book"+str(i),price=30+i*i))
Book.objects.bulk_create(Booklist)
分页器:
paginator = Paginator(book_list, 10)
print("count:",paginator.count) #数据总数
print("num_pages",paginator.num_pages) #总页数
print("page_range",paginator.page_range) #页码的列表
page1=paginator.page(1) #第1页的page对象
for i in page1: #遍历第1页的所有数据对象
print(i)
print(page1.object_list) #第1页的所有数据
page2=paginator.page(2)
print(page2.has_next()) #是否有下一页
print(page2.next_page_number()) #下一页的页码
print(page2.has_previous()) #是否有上一页
print(page2.previous_page_number()) #上一页的页码
# 抛错
#page=paginator.page(12) # error:EmptyPage
#page=paginator.page("z") # error:PageNotAnInteger
''''''
models.py
from django.db import models
# Create your models here.
class Book(models.Model):
title = models.CharField(max_length=32)
price = models.DecimalField(max_digits=8,decimal_places=2)
urls.py
from django.contrib import admin
from django.urls import path
from app01 import views
urlpatterns = [
path(''admin/'', admin.site.urls),
path(''index/'', views.index),
]
七、线上 - cookie session
线上 Cookie session
http://www.cnblogs.com/yuanchenqi/articles/9036467.html
Cookie : 一个浏览器 针对 一个服务器 存储得 key value 值!
在浏览器端得磁盘上存储
默认时间是2周,可设置失效时间! 就算关机开机,cookie任然存在!!
设置Cookie 用响应体 利用cookie 维持会话得记录保存状态!
response = HttpResponse(''登录成功'')
HttpResponse() render() redirect() 三个response 都可设置cookie
# 1. 设置失效时间
response.set_cookie(''is_login'', True, max_age = 15) # 时间 15s 后
import datetime # 固定在哪个时刻 过期
date = datetime.datetime(year=2018,month=5,day=29,hour=14,minute=32,seconds=10)
response.set_cookie(''username'',username,expires=date)
# 2. 有效路径
response.set_cookie(''username'',username,path=''/index/'')
# 3. 清cookie 浏览器
ctrl + shift + delete
# 4. 设置上次访问时间
import datetime
now = datetime.datetime.now().strftime(''%Y-%m-%d %H:%M:%S'')
设置为北京时间
TIME_ZONE = ''UTC''
TIME_ZONE = ''Asia/Shanghai''
last_time = request.COOKIE.get(''last_visit_time'','''')
response.set_cookie(''last_visit_time'',now)
return render(request,''index.html'',{''username'':username,''last_time'':last_time})
# 5.利用cookie设置 上次访问得商品
。。。
return response
is_login = request.COOKIE.get(''is_login'')
if is_login:
username = request.COOKIE.get(''username'')
return render(request,''index.html'',{''username'':username})
else:
return redirect(''/login/'')
-------------------------------------
session:
写:
request.session[''is_login''] = True
request.session[''username''] = "yuan"
import datetime
now = datetime.datetime.now().strftime(''%Y-%m-%d %H:%M:%S'')
request.session[''last_visit_time''] = now
if request.COOKIE.get(''sessionid''):
在django-session表中更新一条记录:
session-key session-data
2312312sadasdasdas2312 {"is_login":True,"username":''alice''}
else:
1. 生成随机字符串
2. response.set_cookie(''sessionid'',2312312sadasdasdas2312)
3. 在django-session表中创建一条记录:
session-key session-data
2312312sadasdasdas2312 {"is_login":True,"username":''yuan''}
读:
request.session.get(''is_login'')
username = request.session.get(''username'')
last_visit_time = request.session.get(''last_visit_time'')
1. request.COOKIE.get(''sessionid'') # 2312312sadasdasdas2312
2. django-session表中得记录过滤
session-key session-data
2312312sadasdasdas2312 {"is_login":True,"username":''yuan''}
obj = djsngo-session.object.filter(session-key="2312312sadasdasdas2312").first()
3. obj.session-data.get(''is_login'')
注销:
del request.session[''is_login''] # 不建议这么做; 要删就要删整条记录
request.session.flush()
1. session_str = request.COOKIE.get(''sessionid'')
2. django-session.object.filter(session-key=session-str).delete()
3. response.delete_cookie(''sessionid'')
session 配置:
Django默认支持Session,并且默认是将Session数据存储在数据库中,即:django_session 表中。
配置 settings.py
SESSION_ENGINE = ''django.contrib.sessions.backends.db'' # 引擎(默认)
SESSION_COOKIE_NAME = "sessionid" # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串(默认)
SESSION_COOKIE_PATH = "/" # Session的cookie保存的路径(默认)
SESSION_COOKIE_DOMAIN = None # Session的cookie保存的域名(默认)
SESSION_COOKIE_SECURE = False # 是否Https传输cookie(默认)
SESSION_COOKIE_HTTPONLY = True # 是否Session的cookie只支持http传输(默认)
SESSION_COOKIE_AGE = 1209600 # Session的cookie失效日期(2周)(默认)
SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 是否关闭浏览器使得Session过期(默认)
SESSION_SAVE_EVERY_REQUEST = False # 是否每次请求都保存Session,默认修改之后才保存(默认)
总结:
1. 写cookie:
response.set_cookie(key,value)
2, 读cookie:
request.COOKIE.get(key)
3. 写session
request.session[key] = value
注意django对应得操作
if request.COOKIE.get(''sessionid''):
在django-session表中更新一条记录:
session-key session-data
2312312sadasdasdas2312 {"is_login":True,"username":''alice''}
else:
1. 生成随机字符串
2. response.set_cookie(''sessionid'',2312312sadasdasdas2312)
3. 在django-session表中创建一条记录:
session-key session-data
2312312sadasdasdas2312 {"is_login":True,"username":''yuan''}
4. 读session:
request.session[key]
1. request.COOKIE.get(''sessionid'') # 2312312sadasdasdas2312
2. django-session表中得记录过滤
session-key session-data
2312312sadasdasdas2312 {"is_login":True,"username":''yuan''}
obj = djsngo-session.object.filter(session-key="2312312sadasdasdas2312").first()
3. obj.session-data.get(''is_login'')
5. 删session:
request.session.flush()
1. session_str = request.COOKIE.get(''sessionid'')
2. django-session.object.filter(session-key=session-str).delete()
3. response.delete_cookie(''sessionid'')
关于Django;如何更改django.contrib.sessions使用的表名?和django修改admin页面的问题就给大家分享到这里,感谢你花时间阅读本站内容,更多关于12 Django cooking与session、25 Jun 18 Django,Cookie,Session,分页(自定义,Django自带)、Django - cookie & session、Django - Cookie、Session、自定义分页和Django分页器等相关知识的信息别忘了在本站进行查找喔。
本文标签: