django知识回顾
一、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()
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的内容以实现复杂的页面,但是还是存在问题:如果给用户返回动态内容
自定义一套特殊的语法,进行替换
使用开源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()
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>
遵循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=="123123": #登录成功 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
<!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',"123123",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=="123": 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 == '123': #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')