一、web框架
1、web框架本质
众所周知,对于所有的web应用,本质上其实就是一个socket服务端,用户的浏览器其实就是一个socket客户端
1、浏览器(socket客户端)
2、发送IP和端口:http://www.baidu.com:80/index/
3、请求方式:
GET:请求头: 如:http1.1 /index?p=123
请求体: 无内容 POSt:请求头 http1.1 /index?p=123
请求体 4、接收响应
普通响应:页面直接显示
重定向响应:再起一次Http请求 服务器(socket服务端)
1、启动并监听ip和端口,等待用户连接
接收请求进行处理,并返回
普通返回:
响应头:
Access-Control-Allow-Origin:*
Cache-Control:max-age=600
Date:Mon, 19 Jun 2017 00:57:43 GMT
Expires:Mon, 19 Jun 2017 01:07:43 GMT
Last-Modified:Wed, 24 May 2017 01:51:55 GMT
Server:GitHub.com
X-GitHub-Request-Id:C495:5EBC:8739EF:B817EE:59472187 响应体:
<html>
....
</html> 重定向返回:
响应头:
LOCATION: 'http://www.baidu.com'
Access-Control-Allow-Origin:*
Cache-Control:max-age=600
Date:Mon, 19 Jun 2017 00:57:43 GMT
Expires:Mon, 19 Jun 2017 01:07:43 GMT
Last-Modified:Wed, 24 May 2017 01:51:55 GMT
Server:GitHub.com
X-GitHub-Request-Id:C495:5EBC:8739EF:B817EE:59472187
WSGI(Web Sever Gateway Interface)是一种规范,它定义了使用python编写的web app与web server之间接口格式,
实现web app与web server间的解耦
2、自定义Web框架
通过python标准库提供的wsgiref模块开发一个自己的Web框架
from wsgiref.simple_server import make_server def index():
return 'index' def login():
return 'login' def routers(): urlpatterns = (
('/index/',index),
('/login/',login),
) return urlpatterns def RunServer(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/html')])
url = environ['PATH_INFO']
urlpatterns = routers()
func = None
for item in urlpatterns:
if item[0] == url:
func = item[1]
break
if func:
return func()
else:
return '404 not found' if __name__ == '__main__':
httpd = make_server('', 8000, RunServer)
print "Serving HTTP on port 8000..."
httpd.serve_forever()
Views
HTML:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body>
<h1>Index</h1> </body>
</html> HTML:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body>
<form>
<input type="text" />
<input type="text" />
<input type="submit" />
</form>
</body>
</html>
html
对于上述代码,虽然可以返回给用户html的内容以实现复杂的页面,但是还是存在问题:如果给用户返回动态内容
自定义一套特殊的语法,进行替换
使用开源jinja2,遵循其指定语法
from wsgiref.simple_server import make_server
from jinja2 import Template def index():
# return 'index' # template = Template('Hello {{ name }}!')
# result = template.render(name='John Doe') f = open('index.html')
result = f.read()
template = Template(result)
data = template.render(name='John Doe', user_list=['alex', 'eric'])
return data.encode('utf-8') def login():
# return 'login'
f = open('login.html')
data = f.read()
return data def routers(): urlpatterns = (
('/index/', index),
('/login/', login),
) return urlpatterns def run_server(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/html')])
url = environ['PATH_INFO']
urlpatterns = routers()
func = None
for item in urlpatterns:
if item[0] == url:
func = item[1]
break
if func:
return func()
else:
return '404 not found' if __name__ == '__main__':
httpd = make_server('', 8000, run_server)
print "Serving HTTP on port 8000..."
httpd.serve_forever()
Views
HTML:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body>
<h1>{{name}}</h1> <ul>
{% for item in user_list %}
<li>{{item}}</li>
{% endfor %}
</ul> </body>
</html>
html
遵循jinja2的语法规则,其内部会对指定的语法进行相应的替换,
从而达到动态的返回内容。
二、DjangoWeb框架
1、介绍Django
django:是一个由python写成的开放源代码的Web应用框架。
1、django
#安装: pip3 install django
添加环境变量 创建project
命令:django-admin startproject mysite
---mysite ---settings.py
---url.py
---wsgi.py
---- manage.py(启动文件) 创建APP
python mannage.py startapp app01
project
- app01
- admin Django自带后台管理相关配置
- modal 写类,根据类创建数据库表
- test 单元测试
- views 业务处理 2、配置文件 a: 静态文件:
在settings里修改添加,放css,js,image等文件
创建static文件夹 STATIC_URL = '/static/' # 相当于别名
STATICFILES_DIRS = [
os.path.join(BASE_DIR,'static'), #切记一定加逗号
] b:模板:
在settings里修改,放HTML文件
TEMPLATE_DIRS = (
os.path.join(BASE_DIR,'templates')
) c:数据库:
# django支持sqlite,mysql, oracle,postgresql数据库
# django默认使用sqlite的数据库,默认自带sqlite的数据库驱动 , 引擎名称:django.db.backends.sqlite3
# 由于Django内部连接MySQL时使用的是MySQLdb模块,而python3中还无此模块,所以需要使用pymysql来代替
# 设置放置的与project同名的配置的 __init__.py文件中 __init__.py 导入 import pymysql
pymysql.install_as_MySQLdb() # 在settings 中修改DATABASES DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'dbname', # 数据库名称
'USER': 'root', # 用户名
'PASSWORD': 'xxx', # 密码
'HOST': '', # IP,留空默认localhost
'PORT': '', # 端口
}
} d:新增app
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'app01',
'app02',
] 3、路由关系
from app01 import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^index.html$', views.index),
] 4、视图函数
def index(request):
request.method
request.GET
request.POST return HttpResponse('字符串')
return redirect('URL')
return render(request,'模板路径',{})
# 1. 获取模板+数据,渲染
# 2. HttpReponse(...) 5、模板渲染
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>模板标记学习</h1>
<p>{{ name }}</p>
<p>{{ users.0 }}</p> //索引取值
<p>{{ users.1 }}</p> //索引取值
<p>{{ user_dict.k1 }}</p>
<p>{{ user_dict.k2 }}</p>
例子:
urlpatterns = [
url(r'^login/', login), #后面配函数
url(r'^index/', index),
] def login(request):
"""
处理用户请求,并返回内容
:param request: 用户请求相关的所有信息(对象)
:return:
"""
#字符串
# return HttpResponse("这个世界很美好".encode("utf8")) #第一种返回字符串类型 #自动找到模板路径下的login.html文件,读取内容并返回给用户
#模板路径的配置 render
if request.method=="GET":
return render(request,'login.html') else:
#用户POST提交的数据(请求体)
u=request.POST.get("user")
p=request.POST.get("pwd")
if u=="root" and p=="":
#登录成功
return redirect("http:www.oldboyde.com") #重定向
else:
#登录失败
return render(request,"login.html",{'msg':'用户名或密码错误'})
# return render(request,'login.html') #参数是什么,就传什么参数,后面也可以加参数 login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="/static/commons.css">
</head>
<body>
<h1>用户登录</h1>
<form method="POST" action="/login/">
<input type="text" name="user" />
<input type="password" name="pwd" />
<input type="submit" value="登录" />
{{ msg }}
</form>
</body>
例子
2、 Ajax:
jQuery其实就是一个JavaScript的类库,其将复杂的功能做了上层封装,使得开发者可以在其基础上写更少的代码实现更多的功能。
jQuery 不是生产者,而是大自然搬运工。
jQuery Ajax本质 XMLHttpRequest 或 ActiveXObject
jQuery.ajax(...) 部分参数:
url:请求地址
type:请求方式,GET、POST(1.9.0之后用method)
headers:请求头
data:要发送的数据
contentType:即将发送信息至服务器的内容编码类型(默认: "application/x-www-form-urlencoded; charset=UTF-8")
async:是否异步
timeout:设置请求超时时间(毫秒) beforeSend:发送请求前执行的函数(全局)
complete:完成之后执行的回调函数(全局)
success:成功之后执行的回调函数(全局)
error:失败之后执行的回调函数(全局) accepts:通过请求头发送给服务器,告诉服务器当前客户端课接受的数据类型
dataType:将服务器端返回的数据转换成指定类型
"xml": 将服务器端返回的内容转换成xml格式
"text": 将服务器端返回的内容转换成普通文本格式
"html": 将服务器端返回的内容转换成普通文本格式,在插入DOM中时,如果包含JavaScript标签,则会尝试去执行。
"script": 尝试将返回值当作JavaScript去执行,然后再将服务器端返回的内容转换成普通文本格式
"json": 将服务器端返回的内容转换成相应的JavaScript对象
"jsonp": JSONP 格式
使用 JSONP 形式调用函数时,如 "myurl?callback=?" jQuery 将自动替换 ? 为正确的函数名,以执行回调函数 如果不指定,jQuery 将自动根据HTTP包MIME信息返回相应类型(an XML MIME type will yield XML, in 1.4 JSON will yield a JavaScript object, in 1.4 script will execute the script, and anything else will be returned as a string
ajax
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.btn{
display: inline-block;
padding: 5px 10px;
background-color: coral;
color: white;
}
</style>
</head>
<body>
<h1>jQuery Ajax</h1>
<h3>GET请求</h3>
<div>
<a class="btn" onclick="AjaxSubmit1();">点我</a>
</div>
<h3>POST请求</h3>
<div>
<a class="btn" onclick="AjaxSubmit3();">点我</a>
</div>
<script>
function AjaxSubmit1() {
$.ajax({
url: '/ajax1.html',
type:'GET',
data: {'p':123},
success:function (arg) { }
})
}
1、 ajax参数
url:
type:
data:
1、value不能是字典 {k1:'v1',k2:[1,2,3,],k3; JSON.string}
2、$('').serilizer()
dataType:"JSON", # text,html,xml
单词太长了 traditional:
success:function(arg) {
#arg=>obj
},
error:function(){
} 2、序列化
JavaScript:
JSON.parse()
JSon.stringify() Django:
json.dumps()
json.loads()
问题:
serilize: model.TB.objects.all()
json: model.TB.objects.value()
json: model.TB.objects.value_list()
3、路由系统
URL配置(URLconf)就像Django 所支撑网站的目录。它的本质是URL模式以及要为该URL模式调用的视图函数之间的映射表;
你就是以这种方式告诉Django,对于这个URL调用这段代码,对于那个URL调用那段代码。
a:单一路由对应
url(r'^index$', views.index),
b:基于正则的路由
url(r'^index/(\d*)', views.index),
url(r'^manage/(?P<name>\w*)/(?P<id>\d*)', views.manage),
c:添加额外的参数
url(r'^manage/(?P<name>\w*)', views.manage,{'id':333}),
d:为路由映射设置名称(反向生成url)
url(r'^home', views.home, name='h1'),
url(r'^index/(\d*)', views.index, name='h2'), urls:
url(r'^index/(\d+)/',views.index,name="n1"),
url(r'^index/(?P<a1>\d+)/',views.index,name="n1"), views:
from django.urls import reverse #根据名字反转成url
def index(request,a1): #一一对应关系
user_list=[
"alex","eric","tony"
]
v=reverse("n1",args=(1,)) #args= 数字自己规定 写的是1 url也会体现出来
and
v=reverse("n1",kwargs={'a1':11111})
print(v)
return render(request,'index.html',{"user_list":user_list}) 在html里写
url(r'^login/',views.login,name='m1'),
<form method="POST" action="{% url "m1" %}"> /* 根据名称也可以反生url*/
url(r'^edit/(\w+)/', views.edit,name='n2')
<li>{{ i }}<a href="{% url 'n2' i %}">| 编辑</a></li> 跳转的时候也可以做,不用写url
e:路由分发
如果映射url太多,全写一个在 urlpatterns 显得繁琐,so 路由分发应用而生 urls.py
url(r'^app01/',include('app01.urls')), 总路由:
url(r'^',default), url不存在的话 可以默认写 or 跳转到index 的路径下
url(r'^',views.index), #路由默认不写 或者路由错误 直接执行index的函数
app01.urls.py
url(r'^index.html$',views.index),
额外:
终止符:^edits$
伪静态:url(r’^edit/(\w+).html$’,views.edit),
4、视图函数(CBV & FBV)
CBV:
# from django.views import View #导入一个 View 以便类继承 # class Login(View): #继承一个特殊的类 View
# """
# 提交方法
# get 查
# post 创建
# put 更新
# delete 删除
# """
#
# def get(self,request): #get请求取值
# return render(request,'login.html')
#
# def post(self,request): #post请求取值
# print(request.POST.get("user"))
# return HttpResponse("Login.post") urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^test.html$',views.test), #url对应函数
url(r'^login.html$',views.Login.as_view()), #url对应类
] <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form method="POST" action="/login.html">
<input type="text" name="user"/>
<input type="submit" value="提交"/>
</form>
</body>
</html>
5、ORM操作:
a.创建表
from django.db import models class User_type(models.Model):
uid = models.BigAutoField(primary_key=True)
title = models.CharField(max_length=32) class User_info(models.Model):
name = models.CharField(max_length=32)
age = models.CharField(max_length=32)
ut = models.ForeignKey("User_type") python manage.py makemigrations python manage.py migrate
---------------------其它--------------------- class part(models.Model):
cid = models.BigAutoField(primary_key=True)
title = models.CharField(max_length=32,null=False) class student(models.Model):
sid = models.BigAutoField(primary_key=True)
name = models.CharField(max_length=32,null=False)
pub_data=models.DateField()
age = models.IntegerField(default=18)
# 新增加的列 如果原先表里有值,写default
ug = models.ForeignKey("part",null=True) #如果新增加外键,加null=True
b:ORM操作:
基本操作:
#增
# models.User_type.objects.create(title="黑金用户") # obj = models.User_type(title="小白用户")
# obj.save() #删
#models.User_type.objects.filter(title="小白用户").delete() # 删除指定条件的数据 #改
#models.User_type.objects.filter(title="黑金用户").update(title="黑卡用户") # 修改指定条件的数据 #查
# models.User_type.objects.get(title="大白用户") # 获取单条数据,不存在则报错(不建议)
# models.User_type.objects.all() # 获取全部
# models.User_type.objects.filter(title="小白用户") # 获取指定条件的数据
# models.User_type.objects.exclude(title="黄金用户") # 排除指定条件的数据
Django--ORM基本操作 请看我的另一篇博客:http://www.cnblogs.com/niejinmei/p/7089719.html
c:多对多操作
方法一:
通过外键创建第三张表
class Boy(models.Model):
name = models.CharField(max_length=32) class Girl(models.Model):
nick = models.CharField(max_length=32) class Love(models.Model):
b = models.ForeignKey("Boy")
g = models.ForeignKey("Girl") class Meta:
unique_together = [
("b","g"),
] #表里插入数据 objs = [
models.Boy(name='方少伟'),
models.Boy(name='游勤斌'),
models.Boy(name='于浩'),
models.Boy(name='陈涛'),
]
models.Boy.objects.bulk_create(objs,4) result = [
models.Girl(nick='于浩姐姐'),
models.Girl(nick='景甜'),
models.Girl(nick='刘亦非'),
models.Girl(nick='苍老师'),
]
models.Girl.objects.bulk_create(result, 4) models.Love.objects.create(b_id=1,g_id=1)
models.Love.objects.create(b_id=1,g_id=2)
models.Love.objects.create(b_id=1,g_id=3)
models.Love.objects.create(b_id=2,g_id=4) ################### 查找和我有关系的女孩 四种方式 ################ obj = models.Boy.objects.filter(name="方少伟").first()
love_list = obj.love_set.all()
for row in love_list:
print(row.g.nick) love_list = models.Love.objects.filter(b__name="方少伟")
for row in love_list:
print(row.g.nick) #下面两个效果好 love_list = models.Love.objects.filter(b__name="方少伟").values("g__nick")
for item in love_list:
print(item["g__nick"]) love_list = models.Love.objects.filter(b__name="方少伟").select_related("g")
for obj in love_list:
print(obj.g.nick)
方法一
通过 ManyToManyField 创建第三张表
class Boy(models.Model):
name = models.CharField(max_length=32)
m = models.ManyToManyField("Girl") class Girl(models.Model):
nick = models.CharField(max_length=32)
obj = models.Boy.objects.filter(name="方少伟").first()
# print(obj.id,obj.name) # obj.m.add(2)
# obj.m.add(1,3)
# obj.m.add(*[4,]) # obj.m.remove(2)
# obj.m.remove(1,3)
# obj.m.remove(*[4,]) # obj.m.set([1,4,]) # girl_list = obj.m.all()
# girl_list = obj.m.filter(nick="苍老师") # obj.m.clear() obj = models.Girl.objects.filter(nick="苍老师").first()
v = obj.boy_set.all()
方法二
方式三:通过 外键 和 ManyToManyField 创建
class Boy(models.Model):
name = models.CharField(max_length=32)
m = models.ManyToManyField("Girl",through="Love",through_fields=("b","g",)) class Girl(models.Model):
nick = models.CharField(max_length=32) class Love(models.Model):
b = models.ForeignKey("Boy")
g = models.ForeignKey("Girl") class Meta:
unique_together = [
("b","g"),
]
obj = models.Boy.objects.filter(name="方少伟").first() #只可以查或清空
obj.m.clear() obj.m.all()
方法三
d:一对多
正向:
filter() values,values_list() -> 跨表 fk__xxx
objs = all()
for obj in objs:
obj.fk. 反向:
filter() values,values_list() -> 跨表 表名称__xxx
objs = all()
for obj in objs:
obj.表名称_set.all()
1、连表操作演示 urlpatterns = [ url(r'^test/', views.test), ] class User_type(models.Model):
uid = models.BigAutoField(primary_key=True)
title = models.CharField(max_length=32) class User_info(models.Model):
name = models.CharField(max_length=32)
age = models.CharField(max_length=32)
ut = models.ForeignKey("User_type") def test(request):
models.User_type.objects.create(title="普通用户")
models.User_type.objects.create(title="白金用户")
models.User_type.objects.create(title="黄金用户") models.User_info.objects.create(name="小鸡",age=18,ut_id=1)
models.User_info.objects.create(name="小狗",age=18,ut_id=2)
models.User_info.objects.create(name="小猫",age=18,ut_id=2)
models.User_info.objects.create(name="小雨",age=18,ut_id=3)
models.User_info.objects.create(name="大雨",age=18,ut_id=1) for i in range(300):
name = "root" + str(i)
models.User_info.objects.create(name=name, age=18, ut_id=1) #正向操作
obj = models.User_info.objects.all().first()
print(obj.name,obj.age,obj.ut.title) #反向操作 obj.表名小写_set.all()
obj = models.User_type.objects.all().first()
for row in obj.user_info_set.all():
print(row.name,row.age) result = models.User_type.objects.all()
for item in result:
print(item.title,item.user_info_set.all())
print(item.user_info_set.filter(name="小雨")) #字典格式
result = models.User_info.objects.all().values("id","name")
for row in result:
print(row) #字典格式查的时候跨表
result = models.User_info.objects.all().values("id","name","ut__title")
for row in result:
print(row["id"],row["name"],row["ut__title"]) # 元组格式
# result = models.User_info.objects.all().values_list("id","name")
# for row in result:
# print(row) return HttpResponse(".....")
e:分页
自带分页
自带分页(适合与上一页、下一页)
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^test.html$',views.test), #url对应函数
url(r'^index.html$',views.index), def index(request):
"""
分页
:param request:
:return:
"""
# for i in range(300) : #向数据库增加数据
# name="root"+str(i)
# models.UserInfo.objects.create(name=name,age=18,ut_id=1) # current_page=request.GET.get("page") #获取当前页
# user_list=models.UserInfo.objects.all() #获取用户所有的信息
# paginator=Paginator(user_list,10) # 分页处理,每页显示十条数据
#per_page:每页显示条目数量
#count:数据总个数
#num_总页数
#page_range:总页数的索引范围,如:(1,10),(1,200)
#page:page对象
# try:
# posts=paginator.page(current_page) #posts是一个对象
# except PageNotAnInteger as e:
# posts=paginator.page(1)
# except EmptyPage as e:
# posts=paginator.page(1) #has_next 是否有下一页
#next_page_number 下一页页码
#has_previous 是否有上一页
#previous_page_number 上一页页码
#object_list 分页之后的数据列表
#number 当前页
#paginator paginator对象 # return render(request,'index.html',{"posts":posts}) <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>用户列表</h1> <ul>
{% for row in posts.object_list %}
<li>{{ row.name }}</li>
{% endfor %}
</ul>
<div>
{% if posts.has_previous %}
<a href="/index.html?page={{ posts.previous_page_number }}">上一页</a>
{% endif %} {% if posts.has_next %}
<a href="/index.html?page={{ posts.next_page_number }}">下一页</a>
{% endif %}
</div>
</body>
</html>
自带分页
自定义分页
自定义分页:
class PageInfo(object):
# def __init__(self,current_page,all_count,per_page,base_url,show_page=11): #show_page=1:10的数
# """
#
# :param current_page: 当前页
# :param all_count: 数据库总行数
# :param per_page: 每页显示行数
# """
#
# try:
# self.current_page=int(current_page) #当前页转成int类型
# except Exception as e:
# self.current_page=1 #当前页显示为1
# self.per_page=per_page
#
# a,b= divmod(all_count,per_page) #总行数除每页显示行数
# if b:
# a=a+1
# self.all_pager=a
# self.show_page=show_page
# self.base_url=base_url
#
# def start(self):
# return (self.current_page-1)*self.per_page
#
# def end(self):
# return self.current_page *self.per_page
#
# def pager(self):
# page_list=[]
# half=int((self.show_page-1)/2) #取前五个的值
#
# #如果数据总页数<11
# if self.all_pager <self.show_page:
# begin=1
# stop=self.all_pager+1
#
# #如果总页数>11
# else:
# #如果当前页 <=5, 永远显示1,11
# if self.current_page <=half:
# begin=1
# stop=self.show_page+1
# else:
# if self.current_page+half > self.all_pager:
# begin=self.all_pager-self.show_page+1
# stop=self.all_pager+1
# else:
# begin=self.current_page - half
# stop=self.current_page + half +1
# if self.current_page <=1:
# prev="<li><a href='#'>上一页</a></li>"
# else:
# prev="<li><a href='%s?page=%s'>上一页</a></li>" %(self.base_url,self.current_page-1,)
# page_list.append(prev)
#
# for i in range(begin,stop):
# if i == self.current_page:
# temp = "<li class='active'><a href='%s?page=%s'>%s</a></li>" %(self.base_url,i,i,)
#
# else:
# temp= "<li><a href='%s?page=%s'>%s</a></li>" % (self.base_url, i, i,)
# page_list.append(temp)
#
# if self.current_page >=self.all_pager:
# nex="<li><a href='#'>下一页</a></li>"
# else:
# nex = "<li><a href='%s?page=%s'>下一页</a></li>" % (self.base_url, self.current_page + 1,)
# page_list.append(nex)
#
# return "".join(page_list) #将列表拼接成字符串
#
#
# def custom(request):
# # 表示用户当前想要访问的页码:
# all_count=models.UserInfo.objects.all().count() #取数据库总个数
# page_info=PageInfo(request.GET.get("page"),all_count,10,'/custom.html',11) #用户传值 #加入用户传一个非数字的类型 可以捕捉异常
# #产生一个对象
# user_list = models.UserInfo.objects.all()[page_info.start():page_info.end()] #对象.方法调用
# return render(request, 'custom.html', {"user_list": user_list,'page_info':page_info})
# ps:自定义的分页的功能写好放在文档里面,以后谁用可以直接导入过来使用
from utils.pager import PageInfo
def custom(request):
# 表示用户当前想要访问的页码:
all_count=models.UserInfo.objects.all().count() #取数据库总个数
page_info=PageInfo(request.GET.get("page"),all_count,10,'/custom.html',11) #用户传值 #加入用户传一个非数字的类型 可以捕捉异常
#产生一个对象
user_list = models.UserInfo.objects.all()[page_info.start():page_info.end()] #对象.方法调用
return render(request, 'custom.html', {"user_list": user_list,'page_info':page_info})
自定义分页
6:COOKIE:
Cookie是存储在用户浏览器上的一个键值对
A、获取cookie
request.COOKIES['key']
request.get_signed_cookie(key, default=RAISE_ERROR, salt='', max_age=None)
request.COOKIES.get(...)
参数:
default: 默认值
salt: 加密盐
max_age: 后台控制过期时间(超时时间)
B、设置Cookies
obj=HttpResponse(....)
obj=render(request,......)
obj.set_cookie(key,value,.....)
cookie签名:
obj.set_signed_cookie(key,value,salt="加盐" 'ticket',"",salt='jjjjjj') 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获取(不是绝对,底层抓包可以获取到也可以被覆盖)
def cookie(request):
# 获取 Cookie
# request.COOKIES 获取所有的COOKIES # 客户端发来的所有Cookie
# request.COOKIES['username111'] # 这个Cookie,就是字典
request.COOKIES.get('username111') # 设置 Cookie
res = render(request,'index.html')
res = redirect('/index/') res.set_cookie('key',"value") # 设置cookie,关闭浏览器失效
res.set_cookie('key',"value",max_age=10) # 设置cookie, N秒后失效 # expires:设置cookie, 截止时间后失效
import datetime
current_date = datetime.datetime.utcnow()
current_date = current_date + datetime.timedelta(seconds=5)
res.set_cookie('key',"value",expires=current_date)
# cookie 加密盐
obj = HttpResponse('s')
obj.set_signed_cookie('username',"kangbazi",salt="asdfasdf") # 加密盐
request.get_signed_cookie('username',salt="asdfasdf") # 加密盐获取
C、cookie认证:
def classes(request,*args,**kwargs):
#去请求的cookie中找凭证
tk=request.COOKIES.get("ticket") #去COOKIES取值
if not tk: #判断没有值 表示没有登录
return redirect("/login/") #跳转到login页面从新登录 def login(request):
if request.method=="GET":
return render(request,'login.html')
else:
user=request.POST.get("username")
pwd=request.POST.get("password")
if user=="alex" and pwd=="":
obj=redirect("/classes/") #登录成功跳转到classes页面
obj.set_cookie('ticket',"hahahahaha") #登录成功的话 为浏览器回写cookie
return obj
else:
return render(request,'login.html') #如果不成功的跳转到登录页面
7、session:
Session是存储在服务器的一组键值对,且它依赖于Cookie,且安全系数比Cookie高
Django中默认支持Session,其内部提供了5种类型的Session供开发者使用:
数据库(默认)
缓存
文件
缓存+数据库
加密cookie
数据库session
Django默认支持Session,并且默认是将Session数据存储在数据库中,即:django_session 表中。
a. 配置 settings.py
SESSION_ENGINE = 'django.contrib.sessions.backends.db' # 引擎(默认) SESSION_COOKIE_NAME = "sessionid" # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串(默认)
SESSION_COOKIE_PATH = "/" # Session的cookie保存的路径(默认)
SESSION_COOKIE_DOMAIN = None # Session的cookie保存的域名(默认)
SESSION_COOKIE_SECURE = False # 是否Https传输cookie(默认)
SESSION_COOKIE_HTTPONLY = True # 是否Session的cookie只支持http传输(默认)
SESSION_COOKIE_AGE = 1209600 # Session的cookie失效日期(2周)(默认)
SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 是否关闭浏览器使得Session过期(默认)
SESSION_SAVE_EVERY_REQUEST = False # 是否每次请求都保存Session,默认修改之后才保存(默认) def index(request):
# 获取、设置、删除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的随机字符串
request.session.session_key # 将所有Session失效日期小于当前日期的数据删除
request.session.clear_expired() # 检查 用户session的随机字符串 在数据库中是否
request.session.exists("session_key") # 删除当前用户的所有Session数据
request.session.delete("session_key") request.session.set_expiry(value)
* 如果value是个整数,session会在些秒数后失效。
* 如果value是个datatime或timedelta,session就会在这个时间后失效。
* 如果value是0,用户关闭浏览器session就会失效。
* 如果value是None,session会依赖全局session失效策略。
b:session认证:
def login(request):
if request.method=="GET":
return render(request,'login.html')
else:
u=request.POST.get("user")
p=request.POST.get("pwd")
if u == 'alex' and p == '':
#1.生成随机的字符串
#2.通过cookie发送给客户端
#3.服务端保存
request.session["username"]='alex'
request.session["email"]="alex3714qq.com"
return redirect('/index/')
else:
return render(request,'login.html',{'msg':"用户名或密码错误"}) def index(request):
#1.获取客户端cookie中的随机字符串
#2.去session中查找有没有随机字符串
#3.去session中查看对应的key的value中是否有username
v=request.session.get("username")
if v:
return HttpResponse('登录成功:%s' %v)
else:
return redirect('/login/')
8、xss跨站脚本攻击
XSS又叫CSS (Cross Site Script) ,跨站脚本攻击。它指的是恶意攻击者往web页面里插入恶意的html代码,
当用户浏览该页之时,嵌入其中web里面的html代码会被执行,从而达到恶意用户的特殊目的。
- 慎用 safe和mark_safe
- 非要用,一定要过滤关键字
9、csrf跨站伪装请求
原理:当访问你需要访问的网址,然后被访问的网址会随机生成一个随机字符串返回给用户。
使用:在FBV情况下使用
from django.views.decorators.csrf import csrf_exempt,csrf_protect 导入模块
1、 settings.py 里面的csrf开启
需要在Form表单里面加上{% csrf_token %} 产生随机字符串并生成input框,加上验证。
** 如果写成{{csrf_token}} 会产生随机字符串 但不会生成input框 ** 目前使用不上 作为了解 2、 全部禁用就直接注释掉
# 'django.middleware.csrf.CsrfViewMiddleware', 3、 局部禁用
前提是在全部使用的情况下才能局部禁用
django.middleware.csrf.CsrfViewMiddleware', 单独在某个函数上面加上装饰器 @csrf_exempt
@csrf_exempt
def csrf1(request):
if request.method=="GET":
return render(request, "csrf1.html") else:
return HttpResponse("OK") 4、 局部使用
前提是全部禁用的情况下
# 'django.middleware.csrf.CsrfViewMiddleware', 单独在某个函数上面加上装饰器@csrf_protect
@csrf_protect #局部使用
def csrf1(request):
if request.method=="GET":
return render(request, "csrf1.html") else:
return HttpResponse("OK")
在CBV情况下验证使用
from django.utils.decorators import method_decorator
#CBV应用装饰器
def wrapper(func):
def inner(*args,**kwargs):
func(*args,**kwargs)
return inner #1.指定方法上面加装饰器
# class Foo(View):
# @method_decorator(wrapper)
# def get(self):
# pass
#
# def post(self):
# pass #2.在类上面加装饰器
# @method_decorator(wrapper,name='dispatch')
# class Foo(View):
#
# def get(self):
# pass
#
# def post(self):
# pass #csrf必须加在类上
# @method_decorator(csrf_protect,name='dispatch')
# class Foo(View):
#
# def get(self):
# pass
#
# def post(self):
# pass
############# Ajax提交数据时候,携带CSRF: ###########
1、放置在data中携带
<form method="POST" action="csrf1.html">
{% csrf_token %}
<input id="user" type="text" name="user">
<input type="submit" value="提交">
<a onclick="submitForm();">Ajax提交</a>
</form>
<script src="/static/jquery-3.2.1.js"></script> <script>
function submitForm() {
var csrf=$('input[name="csrfmiddlewaretoken"]').val(); //取字符串的值
var user=$('#user').val(); //取user的值
$.ajax({
url:"/csrf1.html",
tpye:"POST",
data:{"user":user,"csrfmiddlewaretoken":csrf},
success:function (arg) {
console.log(arg);
}
})
}
</script> 2、通过请求头 headers 携带数据 function submitForm() {
var token=$.cookie("csrftoken"); //获取cookie值
var user=$("#user").val(); //获取用户值
$.ajax({
url:"/csrf1.html",
type:"POST",
headers:{"X-CSRFToken":token}, //请求头把数据带过去
data:{"user":user},
success:function (arg) {
console.log(arg)
}
})
}
10、模板语言:
{{ item }}
{% for item in item_list %} <a>{{ item }}</a> {% endfor %}
forloop.counter
forloop.first
forloop.last
{% if ordered_warranty %} {% else %} {% endif %}
母板:{%block css%}
{% block title %}{% endblock %}
{%block js%}
子板:{% extends "base.html" %}
{% block title %}{% endblock %}
模板自定义函数simple_tag:
a、在app中创建templatetags模块 b、创建任意 .py 文件,如:xx.py
from django import template
from django.utils.safestring import mark_safe register = template.Library() @register.simple_tag
def my_simple_time(v1,v2,v3):
return v1 + v2 + v3 @register.simple_tag
def my_input(id,arg):
result = "<input type='text' id='%s' class='%s' />" %(id,arg,)
return mark_safe(result) c、在使用自定义simple_tag的html文件中导入之前创建的 xx.py 文件名
{% load xx %} d、使用simple_tag
{% my_simple_time 1 2 3%}
{% my_input 'id_username' 'hide'%}
-simple_filter -最多两个参数,方式:{{ 第一参数|函数名称:”第二个参数”}}
-可以做条件判断
-simple_tag
-无限制:{%函数名 参数 参数 %}
include:引用小组件随时能使用,导入小组件使用,可以导入多个
{%include 模板名称%}
11、自关联
a:自关联,通过名字大概就知道是一张表要关联它自己本身,如果按照以前学的知识创表时肯定不能成功,这就要运用到今天新学的知识点。
related_name
b:想想,咱们以前关联表时都是在创建一个关系表里边设置外键,自关联也一样。
class UserInfo(models.Model):
nickname = models.CharField(max_length=32)
username = models.CharField(max_length=32)
password = models.CharField(max_length=32)
gender_list=(
(1,'男'),
(2,'女'),
)
gender = models.IntegerField(choices=gender_list) class UtU(models.Model):
g=models.ForeignKey('UserInfo',null=True,related_name='boy')
b=models.ForeignKey('UserInfo',null=True,related_name='grily') 重点在于related_name 这样就相当于给他们设置了别名,数据库就不会分不清谁是谁的关联
c:重点来了,表已经创好了,数据也存在怎么查看相关联的信息啊?
def indexs(request):
tt= models.UserInfo.objects.filter(id=2).first()
print(tt)
# 获取Boy表中id等于2的obj对象(Boy的obj对象)
xx =tt.grily.all()
# 获取UTU表中的所有和Boy对象相关的所有对象
print(xx)
for i in xx:
print(i.g.nickname)
# 循环获取UTU对象g外键对应的名称
return HttpResponse('ok')
def indexss(request):
tt=models.UserINfo.objects.filter(id=2).first()
xx = tt.userinfo_set.all()
## 反向查看关系自关联的表
for i in xx:
print(i.nickname)
return HttpResponse('ok')
d:我们在通过ManyToManyField自动创建一个自关联的关系表。
class UserINfo(models.Model):
nickname = models.CharField(max_length=32)
username = models.CharField(max_length=32)
password = models.CharField(max_length=32)
gender_list=(
(1,'男'),
(2,'女'),
)
gender = models.IntegerField(choices=gender_list)
m = models.ManyToManyField('UserINfo')
def indexsz(request):
tt = models.UserINfo.objects.filter(id=2).first()
# 正向查看自关联表的内容
xx =tt.m.all()
# 获取到和UserINfo相关的UserINfo对象
for i in xx:
print(i.nickname)
return HttpResponse('ok')
正向查看自关联信息
def indexs(request):
tt =models.UserINfo.objects.filter(id=2).first()
ss=tt.userinfo_set.all()
print(ss)
for i in ss:
print(i.nickname)
反向查看自关联信息
12、FK(外键关联)
外键关联就是表(本身)设置一个外键,这个外键要关联的列是这个表(本身)的自增id
class User(models.Model):
new_id=models.IntegerField(null=True)
new_tabe= models.CharField(max_length=32)
new_content =models.CharField(max_length=64)
new_root = models.CharField(max_length=32)
content = models.ForeignKey('User',null=True,blank=True,related_name='xxx')
def indexss(request):
xx =models.User.objects.filter(id=1).first()
xs =models.User.objects.filter(id=2).first()
tt =xx.xxx.all()
ts =xs.xxx.all()
for i in tt:
print(i.new_content)
for i in ts:
print(i.new_content)
return HttpResponse('ok')