Django - Cookie、Session、自定义分页和Django分页器

时间:2024-08-16 14:07:38
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、Session、自定义分页和Django分页器

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流程解析

Django - Cookie、Session、自定义分页和Django分页器

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 class="active"><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 class="active"><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>

五、示例

Django - Cookie、Session、自定义分页和Django分页器

Django - Cookie、Session、自定义分页和Django分页器

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':'',
}
} # 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',
},
}
}

settings

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),
]

urls

BMS __init__.py

import pymysql
pymysql.install_as_MySQLdb()

init

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()

models

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 == '': # 登录成功
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 == '':
# 利用session 保存一个login=alex
request.session['user'] = 'alex'
request.session['login'] = ''
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 class="disabled"><a href="/publisher_list/?page={0}"><span aria-hidden="true">&laquo;</span></a></li>'.format(
# current_page))
# else:
# li.append('<li><a href="/publisher_list/?page={0}"><span aria-hidden="true">&laquo;</span></a></li>'.format(
# current_page - 1))
# for i in range(page_start,page_end+1):
# if i == current_page:
# tmp = '<li class="active"><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 class="disabled"><a href="/publisher_list/?page={0}"><span aria-hidden="true">&raquo;</span></a></li>'.format(
# current_page))
# else:
# li.append('<li><a href="/publisher_list/?page={0}"><span aria-hidden="true">&raquo;</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)

views

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

tests

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>

book_list

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>

book_list2

templates home.html

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

home

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>

login

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/ #}

publisher_list

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 class="disabled"><a href="#"><span aria-hidden="true">&laquo;</span></a></li>')
else:
li.append('<li><a href="{0}?page={1}"><span aria-hidden="true">&laquo;</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 class="active"><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 class="disabled"><a href="#"><span aria-hidden="true">&raquo;</span></a></li>')
else:
li.append('<li><a href="{0}?page={1}"><span aria-hidden="true">&raquo;</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)

mypage

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)

myscript

https://github.com/alice-bj/BMS

六、线上 - Django分页器

Django - Cookie、Session、自定义分页和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>

index

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

示例:

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')