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 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>
五、示例
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 class="disabled"><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 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">»</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 class="disabled"><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 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">»</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')