python&&Django框架&&学习笔记三
分页的实现
配置web models.py
from django.db import models
# Create your models here.
class Host(models.Model):
HostName = models.CharField(max_length=256)
ip = models.GenericIPAddressField()
配置web urls.py
"""LearnDjangoThree URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/2.2/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
from web import views
urlpatterns = [
path('index/<int:page>', views.index),
]
配置web views.py
from django.shortcuts import render
from django.shortcuts import render_to_response
from django.shortcuts import HttpResponse
from web import models
from web import html_helper
#引用mark_safe模块,令html标签等代码内容不干扰正常python逻辑代码
from django.utils.safestring import mark_safe
# Create your views here.
def index(request,page):
#捕捉page的类型,确保page总是为正整形
try:
page = int(page)
except Exception:
page = 1
count = models.Host.objects.all().count()
pageObj = html_helper.PageInfo(page,count,)
rcvData = models.Host.objects.all()[pageObj.start:pageObj.end]
rcvCount = models.Host.objects.all()[pageObj.start:pageObj.end].count()
pageEle = html_helper.Pager(page,pageObj.all_page_count)
ret = {'status':'','data':rcvData,'rcvCount':rcvCount,'page':page,'pageEle':pageEle}
return render_to_response('web/index.html',ret)
配置web html_helper.py
#!/usr/bin/env python
#coding:utf-8
from django.utils.safestring import mark_safe
#文件html_helper.py:用于存放操控html页面的常用函数。
#定义类PageInfo,完成分页数据(页数)的计算
class PageInfo(object):
'''
current_page:当前页
all_count:总数据条数
per_item:每页条数(默认是5)
start:从数据库取范围数据的起始位置
end:从数据库取范围数据的结束位置
all_page_count:全部数据库数据总共可分为多少个分页
'''
def __init__(self,current_page,all_count,per_item=5):
self.CurrentPage = current_page
self.AllCount = all_count
self.PerItem = per_item
#使用装饰器"@property",调用该函数时可省略函数名后面的"()".即"pageObj.start()">"pageObj.start"
@property
def start(self):
return (self.CurrentPage-1)*self.PerItem
@property
def end(self):
return self.CurrentPage*self.PerItem
@property
def all_page_count(self):
temp = divmod(self.AllCount, self.PerItem)
if temp[1] == 0:
all_page_count = temp[0]
else:
all_page_count = temp[0] + 1
return all_page_count
#定义函数Pager.:生成首页、上一个、123、下一页、尾页的HTML
def Pager(page,all_page_count):
'''
page:当前是第几个分页
all_page_count:当前一共有多少分页
'''
#定义列表page_html:存放html页面的元素标签
page_html = []
#定义首页
first_html = "<a href='/web/index/%d'>首页</a>" %(1,)
page_html.append(first_html)
#定义上一页
if page <= 1:
#如果当前页小于等于1,此时点上一页则不进行任何操作
prv_html = "<a href='#'>上一页</a>"
else:
prv_html = "<a href='/web/index/%d'>上一页</a>" %(page-1,)
page_html.append(prv_html)
#定义分页1 分页2 分页3
#定义分页段首分页
begin = 0
#定义分页段末分页
end = 0
#定义分页段长度为5
#定义,默认html仅显示5个分页标签
if all_page_count < 5:
begin = 0
end = all_page_count
else:
if page < 3:
begin = 0
end = page + 2
else:
begin = page-3
if page + 2 < all_page_count:
end = page + 2
else:
end = all_page_count
for i in range(begin,end):
if page == i+1:
a_html = "<a href='/web/index/%d' class='selected' >%d</a>" %(i+1,i+1)
else:
a_html = "<a href='/web/index/%d'>%d</a>" %(i+1,i+1)
page_html.append(a_html)
#定义下一页
if page >= all_page_count:
next_html = "<a href='#'>下一页</a>"
else:
next_html = "<a href='/web/index/%d'>下一页</a>" %(page+1,)
page_html.append(next_html)
#定义尾页
last_html = "<a href='/web/index/%d'>尾页</a>" %(all_page_count,)
page_html.append(last_html)
#整合列表page_html并与返回
#使用mark_safe:返回有效的html元素标签pageEle。不使用mark_safe:在html页面输出代码段
#使用join:将一个个的html元素标签用空格连接成一个大的字符串
pageEle =mark_safe("".join(page_html))
return pageEle
配置templates web index.html
<!doctype html>
<html>
<head>
<!--对页面编码进行设置-->
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<!--兼容IE6浏览器-->
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
<title>demo 10</title>
<style>
.hide{
display:none;
}
.clearfix:after{
content:".";
display:block;
height:0;
clear:both;
visibility:hidden;
}
body
{
font-size:.85em;
font-family:"Trebuchet MS",Verdana,Helvetica;
color:#232323;
background-color:#fff;
}
#Pageing A{
background-color:#008844;
border:1px solid White;
text-decoration:none;color:White;
padding: .1em .6em .2em .6em;
}
#Pageing A.selected{
background-color:#AA7700;
}
</style>
</head>
<body>
<h1>主机信息</h1>
<table border="1">
{% for item in data %}
<tr>
<td>{{item.HostName}}</td>
<td>{{item.ip}}</td>
</tr>
{% endfor %}
</table>
<div>共计{{rcvCount}}条</div>
<div id="Pageing" >{{pageEle}}</div>
<!--引入jQuery文件-->
<script src="jquery-1.11.0.min.js"></script>
<script type="text/javascript">
</script>
</body>
</html>
Cookie与Session
关于Cookie
获取cookie:
request.COOKIES[key]
设置cookie:
response.set_cookie(key,value)
由于cookie保存在客户端的电脑上,所以,jquery也可以操作cookie
Cookie使用示例
cookie示例框架
配置web urls.py文件
from django.contrib import admin
from django.urls import path
from web import views
urlpatterns = [
path('index/<int:page>', views.index),
]
配置web index.htm文件,在浏览器本地存放cookie数据
<!doctype html>
<html>
<head>
<!--对页面编码进行设置-->
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<!--兼容IE6浏览器-->
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
<title>demo 10</title>
<style>
.hide{
display:none;
}
.clearfix:after{
content:".";
display:block;
height:0;
clear:both;
visibility:hidden;
}
body
{
font-size:.85em;
font-family:"Trebuchet MS",Verdana,Helvetica;
color:#232323;
background-color:#fff;
}
#Pageing A{
background-color:#008844;
border:1px solid White;
text-decoration:none;color:White;
padding: .1em .6em .2em .6em;
}
#Pageing A.selected{
background-color:#AA7700;
}
</style>
</head>
<body>
<h1>主机信息</h1>
<table border="1">
{% for item in data %}
<tr>
<td>{{item.HostName}}</td>
<td>{{item.ip}}</td>
</tr>
{% endfor %}
</table>
<div>共计{{rcvCount}}条</div>
<div id="Pageing" >{{pageEle}}</div>
<!--cookie使用示例-->
<div>
<!--当设置好一个分页的显示数据数量时,将数据以cookie的方式存储在浏览器本地-->
<select id="s1" onchange='ChangePageItem(this);'>
<option value='2'>2</option>
<option value='4'>4</option>
<option value='6'>6</option>
<option value='8'>8</option>
</select>
</div>
<!--引入jQuery文件-->
<script src="/static/jquery/jquery-1.11.0.min.js"></script>
<script src="/static/jquery/jquery.cookie.js"></script>
<script type="text/javascript">
//客户端html加载时,获取cookie中存放的分页数据数量。
$(function(){
var per_item = $.cookie("pager_num");
if(per_item){
$("#s1").val(per_item)
}
})
function ChangePageItem(arg){
//创建或修改cookie值,此处需要导入jquery-1.11.0.min.js或jquery.cookie.js插件
//key为pager_num,value为30,存储路径为根目录
//根目录代表全部app的url都可以使用该cookie存储的数据,
//也可以使用{path:'/web'}的方式进允许某个app访问使用该cookie存储的数据
var value = $(arg).val();
$.cookie("pager_num",value,{path:'/'});
//强制刷新当前页面
location.reload()
}
</script>
</body>
</html>
配置web views.py文件.读取浏览器存储的cookie值并渲染新的html页面
from django.shortcuts import render
from django.shortcuts import render_to_response
from django.shortcuts import HttpResponse
from web import models
from web import html_helper
#引用mark_safe模块,令html标签等代码内容不干扰正常python逻辑代码
from django.utils.safestring import mark_safe
# Create your views here.
def index(request,page):
#获取cookie.获取pager_num的值,若未获取到,默认值为5
per_item = int(request.COOKIES.get('pager_num',5))
#捕捉page的类型,确保page总是为正整形
try:
page = int(page)
except Exception:
page = 1
count = models.Host.objects.all().count()
pageObj = html_helper.PageInfo(page,count,per_item)
rcvData = models.Host.objects.all()[pageObj.start:pageObj.end]
rcvCount = models.Host.objects.all()[pageObj.start:pageObj.end].count()
pageEle = html_helper.Pager(page,pageObj.all_page_count)
ret = {'status':'','data':rcvData,'rcvCount':rcvCount,'page':page,'pageEle':pageEle}
response = render_to_response('web/index.html',ret)
#设置cookie
response.set_cookie('pager_num',per_item)
return response
关于Session
获取session:
request.session[key]
设置session:
request.session[key] = value
删除session:
del request[key]
session使用示例
session示例框架
配置sessionDemo urls.py文件
from django.contrib import admin
from django.urls import path
from sessionDemo import views
urlpatterns = [
path('login/', views.login),
path('index/', views.index),
path('logout/', views.logout),
]
配置sessionDemo views.py文件。
from django.shortcuts import render
from django.shortcuts import render_to_response
from django.shortcuts import HttpResponse
from django.shortcuts import redirect
import requests
import json
# Create your views here.
def login(request):
if request.method == "POST":
user = request.POST.get("username")
pwd = request.POST.get("password")
if user == 'dfq' and pwd == '123123':
#当用户身份合法时,将登陆状态存储到session内
request.session['is_login'] = {'user':user}
return redirect('/sessionDemo/index/')
else:
return render_to_response('sessionDemo/login.html',{'msg':'用户名或密码错误'})
return render_to_response('sessionDemo/login.html')
#后台管理的主页面
def index(request):
#通过session判断当前用户是否是登陆状态
try:
is_login = request.session['is_login']
except Exception:
return render_to_response('sessionDemo/login.html',{'msg':'非法用户,给我滚回去登陆'})
if is_login:
return render_to_response('sessionDemo/index.html',{'username':is_login['user']})
else:
return render_to_response('sessionDemo/login.html',{'msg':'非法用户,给我滚回去登陆'})
def logout(request):
#销毁session
try:
del request.session['is_login']
except Exception:
pass
return redirect('/sessionDemo/login/')
配置sessionDemo login.html文件。系统登录页面
<!doctype html>
<html>
<head>
<!--对页面编码进行设置-->
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<!--兼容IE6浏览器-->
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
<title>demo 10</title>
<style>
.hide{
display:none;
}
.clearfix:after{
content:".";
display:block;
height:0;
clear:both;
visibility:hidden;
}
</style>
</head>
<body>
<h1>使用session保存用户会话</h1>
<form method="POST" action="/sessionDemo/login/">
<p>用户名:<input name="username" /></p>
<p>密码:<input name="password" /></p>
<input type="submit" value="提交" />
<label style='color:red;'>{{msg}}</label>
</form>
<!--引入jQuery文件-->
<script src="jquery-1.11.0.min.js"></script>
<script type="text/javascript">
</script>
</body>
</html>
配置sessionDemo index.html页面。系统主页面
<!doctype html>
<html>
<head>
<!--对页面编码进行设置-->
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<!--兼容IE6浏览器-->
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
<title>demo 10</title>
<style>
.hide{
display:none;
}
.clearfix:after{
content:".";
display:block;
height:0;
clear:both;
visibility:hidden;
}
</style>
</head>
<body>
<h1>当前登录用户:{{username}}</h1>
<form method="POST" action="/sessionDemo/logout/">
<input type="submit" value="退出" />
</form>
<!--引入jQuery文件-->
<script src="jquery-1.11.0.min.js"></script>
<script type="text/javascript">
</script>
</body>
</html>
cookie与session的区别
- cookie存在客户端的浏览器上();session存在服务器上(位置任意指定,如内存、数据库、缓存等)
- session用于保持会话(如维持登录状态,无论进行任何操作都能获取到当前用户的登录信息)
- session存储的数据有效时间默认是两周
- session与cookie通常是混合使用的
跨站请求伪造的使用
django为用户实现防止跨站请求伪造功能,通过中间件django.middleware.CsrfViewMiddleware来完成,而对于Django中设置防跨站请求伪造功能有分为全局和局部。
全局:
中间件:django.middleware.csrf.CsrfViewMiddleware
局部:
@csrf_protect,为当前函数强制设置防跨站请求伪造功能,即便settings中没有设置全局中间件
@csrf_exempt,取消当前函数防跨站请求伪造功能,即便settings中设置了全局中间件
配置settings.py文件
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',
]
当“‘django.middleware.csrf.CsrfViewMiddleware’,”没有注销时,在Django框架中使用POST方法时,需要用户身份验证。
token:token可以理解为是一段用于用户身份合法性验证的字符串。
request:request又被称为请求上下文对象
配置sessionDemo views.py文件。对上下文对象request封装并返回token
from django.shortcuts import render
from django.shortcuts import render_to_response
from django.shortcuts import HttpResponse
from django.shortcuts import redirect
import requests
import json
#RequestContext进荣誉室了
#from django.template.context import RequestContext
from django.template.context_processors import csrf
# Create your views here.
def login(request):
if request.method == "POST":
user = request.POST.get("username")
pwd = request.POST.get("password")
if user == 'dfq' and pwd == '123123':
#当用户身份合法时,将登陆状态存储到session内
request.session['is_login'] = {'user':user}
return redirect('/sessionDemo/index/')
else:
return render_to_response('sessionDemo/login.html',{'msg':'用户名或密码错误'},context=csrf(request))
##(该行荣誉室了)#使用"context_instance=RequestContext(request)",在客户端保存用于用户身份合法性验证的cookie数据
#通过csrf(request)对请求上下文对象request封装并返回(其中包含存储在cookie中的csrftoken数据)。
return render_to_response('sessionDemo/login.html',context=csrf(request))
#后台管理的主页面
def index(request):
#通过session判断当前用户是否是登陆状态
try:
is_login = request.session['is_login']
except Exception:
return render_to_response('sessionDemo/login.html',{'msg':'非法用户,给我滚回去登陆'})
if is_login:
return render_to_response('sessionDemo/index.html',{'username':is_login['user']})
else:
return render_to_response('sessionDemo/login.html',{'msg':'非法用户,给我滚回去登陆'})
def logout(request):
#销毁session
try:
del request.session['is_login']
except Exception:
pass
return redirect('/sessionDemo/login/')
配置sessionDemo login.html文件,将cookie中的token数据放到form表单中提交
<!doctype html>
<html>
<head>
<!--对页面编码进行设置-->
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<!--兼容IE6浏览器-->
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
<title>demo 10</title>
<style>
.hide{
display:none;
}
.clearfix:after{
content:".";
display:block;
height:0;
clear:both;
visibility:hidden;
}
</style>
</head>
<body>
<h1>使用session保存用户会话</h1>
<form method="POST" action="/sessionDemo/login/">
<!--csrf_token需要包含在form表单中一起提交-->
{% csrf_token %}
<p>用户名:<input name="username" /></p>
<p>密码:<input name="password" /></p>
<input type="submit" value="提交" />
<label style='color:red;'>{{msg}}</label>
</form>
<!--引入jQuery文件-->
<script src="jquery-1.11.0.min.js"></script>
<script type="text/javascript">
</script>
</body>
</html>
token与Ajax结合提交的方法,配置sessionDemo login.html文件
<!doctype html>
<html>
<head>
<!--对页面编码进行设置-->
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<!--兼容IE6浏览器-->
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
<title>demo 10</title>
<style>
.hide{
display:none;
}
.clearfix:after{
content:".";
display:block;
height:0;
clear:both;
visibility:hidden;
}
</style>
</head>
<body>
<h1>使用session保存用户会话</h1>
<form method="POST" action="/sessionDemo/login/">
<!--csrf_token需要包含在form表单中一起提交-->
{% csrf_token %}
<p>用户名:<input name="username" /></p>
<p>密码:<input name="password" /></p>
<input type="submit" value="提交" />
<label style='color:red;'>{{msg}}</label>
</form>
<input type="button" onclick="Do();" value="Do it"/>
<!--引入jQuery文件-->
<script src="/static/jquery/jquery-1.11.0.min.js"></script>
<script src="/static/jquery/jquery.cookie.js"></script>
<script type="text/javascript">
var csrftoken = $.cookie('csrftoken');
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});
function Do(){
$.ajax({
url:"/sessionDemo/login/",
data:{id:1},
type:'POST',
success:function(data){
console.log(data);
}
});
}
</script>
</body>
</html>
中间件
中间件可以定义四个方法,分别是:
- process_request(self,request)
- process_view(self,request,callback,callback_args,callback_kwargs)
- process_exception(self,request,exception)
- process_response(self,request,response)
以上方法的返回值可以是None和HttpResponse对象,如果是None,则继续按照Django定义的规则向下执行,如果是HttpResponse,则直接将该对象返回给用户
admin的使用方法
在创建表后,方便对表的增删改查
Django admin是Django提供的一个后台管理页面,改善管理页面提供完善的HTML和css,使得你在通过model创建完数据库后,就可以对数据进行增删改查,而使用Django admin则需要以下步骤:
创建后台管理员
python manage.py createsuperuser