写在前面
上课第19天,打卡:
忠于你的理想,别想生活妥协,让挣扎变得有意义!
################ # 2017-09-03 - 课上笔记 ################ class day19: def __init__(): pass def do_homework(): pass def do_my_project(): pass ‘‘‘Django 回顾‘‘‘ - http请求周期 浏览器(socket客户端) 2.socket.connect(ip,port) 进行连接 3.socket.send("http://www.qq.com/index.html...") url + data 遵循的规则:http协议 请求头 请求体 请求头和请求体使用 ‘\r\n\r\n‘ 分隔,前面是请求头,后面是请求体 GET请求: "GET /index.html?key=1... Http/1.1\r\nhost:www.qq.com\r\ncontent-type:application/json\r\n\r\n" POST请求:"POST /index.html Http/1.1\r\nhost:www.qq.com\r\ncontent-type:application/json\r\n\r\nname=alex&pwd=123" 6.获取响应 响应头,响应体 = data.split("\r\n\r\n") 响应头之间用 ‘\r\n‘ 分隔 7.断开连接 nginx(socket服务端) 1.server.run(),监听IP和PORT 4.server.recv() 请求头,请求体 = data.split("\r\n\r\n") request.POST.get(‘name‘) 即是从 请求体 里取值 5.服务端进行响应: conn.send(‘......‘) 遵循的规则:http协议 响应头 响应体 7.断开连接 总结: a.Http请求中本质都是字符串 b.Http请求是短连接(请求 -> 响应 -> 断开连接) c.请求和响应都有头和体 请求:请求头‘\r\n\r\n‘请求体 响应:响应头‘\r\n\r\n‘响应体 由于需要处理繁琐http的解析和封装处理工作,所以web框架应运而生 web框架 - Django socket(wsgiref) django没有自己写socket 解析和封装http请求 django-admin startproject mysite cd mysite python manage.py startapp app01 coding...(*****) python manage.py runserver ip:port ‘‘‘写代码‘‘‘ - 路由系统 /login/ func name=‘f1‘ /login/\d+/ func name=‘f2‘ /login/(?P<n>\d+)/ func name=‘f3‘ /login/\d+/ include(‘app01.urls‘) - 视图函数 def index(request): request.GET request.body 原生的请求体 request.POST 转换后的请求体字典 如果请求头中content-type=urlencode-form... 才将request.body转换成字典 - 可能有值 - 也可能没有值 request.method request.Meta request.GET.get() request.GET.getlist() 前端多选的情况,如多个作者 request.POST.get() request.POST.getlist() return HttpResponse(‘字符串/字节‘) return render(request,"html路径",locals()) return redirect("url") - 模板 for if 继承 filter,simple_tag - Models操作 - 创建表 - models.xxx.objects.create(name="xxxx") - models.xxx.objects.create(**dic) - models.xxx.objects.filter(id__gt=1).delete() - models.xxx.objects.filter(id=1) - models.xxx.objects.exclude(id=5) 取出id不等于5的 - models.xxx.objects.filter(id=1).update(name=‘ddd‘) - models.xxx.objects.filter(id=1).update(**dic) queryset --> [对象,对象...] objs = models.xxx.objects.all() queryset --> [{},{}...] objs = models.xxx.objects.all().values() queryset --> [(),()...] objs = models.xxx.objects.all().values_list() demo1 业务线表 bussiness_unit id name 主机表 serverinfo id host port bs(业务线对象) objs = modesl.serverinfo.objects.all() for row in objs: print(row.id) print(row.host) print(row.port) print(row.bs.name) 外键,拿到业务线的名字 objs = modesl.serverinfo.objects.all().values("id","host","port","bs__name") for row in objs: print(row[‘host‘]) print(row[‘bs__name‘]) demo2 (userinfo 和 bussiness_unit 是多对多关系) 用户表 userinfo id user pwd email mm(ManyToMany) 业务线表 bussiness_unit id name 主机表 id host port bs(业务线对象) 用户业务线关系表 ***** id user_id bs_id obj = models.user.objects.filter(user=‘alex‘).first() obj.mm.add(1) obj.mm.add(11) - 通过用户对象查所负责的所有业务线对象 obj = models.user.objects.filter(user=‘alex‘).first() queryset = obj.mm.all() 拿到alex负责的所有业务线 -> [业务线对象,业务线对象...] for row in queryset: print(row.id) print(row.name) - 通过业务线反查对应有哪些人负责? (***反查*** 表名_set) obj = models.bussiness_unit.objects.filter(name=‘二手车‘).first() queryset = obj.userinfo_set.all() 拿到负责二手车业务线的用户对象 -> [用户对象,用户对象...] for row in queryset: print(row.user) print(row.pwd) 总结: 1.多对多关系建在哪张表上都可以; 2.如果建在userinfo表上,那么通过用户对象查所负责的bs对象列表就直接用 obj.mm.all() 方便了 userinfo对象,但是bs对象反查userinfo就得用 userinfi_set.all() ================================================================== 今日内容: 1.登录 - 密码加密,对密码进行比较 - 用户登录之后才能访问某些页面 2.cookie是什么? - 保存在客户端浏览器上的键值对 {k:v} - cookie依附在请求头或者响应头中 - 浏览器发送请求时会自动携带所访问网站对应的cookie - 应用 - 实现登录 - 投票 - 每页显示10条/20条... - 使用 - 设置 response = redirect(‘/index/‘) response.set_cookie(‘my_cookie‘,md5.encrypt(‘xxx‘)) return response key, value=‘‘, max_age=None, 超时时间:秒数 expires=None, 超时时间:截止日期 path=‘/‘, cookie在哪个url里生效 : 访问指定url时才能读取到cookie, ‘/‘ 表示全部页面都可以 domain=None, 当前域名或者二级域名 secure=False, https httponly=False response = redirect(‘/index/‘) # 设置cookie response.set_cookie(‘my_cookie‘,md5.encrypt(user)) return response # 设置cookie过期时间 import datetime deadline = datetime.datetime.utcnow() + datetime.timedelta(seconds=5) response.set_cookie(‘my_cookie‘,md5.encrypt(user),expires=deadline) response.set_cookie(‘my_cookie‘,md5.encrypt(user),max_age=5) - 获取 ck = request.COOKIES.get(‘my_cookie‘) # 详细代码如下: ‘‘‘ # models.py from django.db import models # Create your models here. class UserInfo(models.Model): username = models.CharField(max_length=32) password = models.CharField(max_length=64) email = models.EmailField(null=True) ‘‘‘ ‘‘‘ from django.shortcuts import render,HttpResponse,redirect from app01 import models from common import md5 # 判断用户是否登录的装饰器(通过cookie判断) def auth(func): def inner(request,*args,**kwargs): ck = request.COOKIES.get(‘my_cookie‘) if not ck: return redirect(‘/login/‘) return func(request,*args,**kwargs) return inner @auth def index(request): user = request.COOKIES.get(‘my_cookie‘) print(request.COOKIES) # return HttpResponse("登录成功") return render(request,‘index.html‘,locals()) def login(request): if "GET" == request.method: return render(request,‘login.html‘) else: user = request.POST.get(‘user‘) pwd = request.POST.get(‘pwd‘) obj = models.UserInfo.objects.filter(username=user,password=md5.encrypt(pwd)).first() if obj: response = redirect(‘/index/‘) # 设置cookie过期时间 # import datetime # deadline = datetime.datetime.utcnow() + datetime.timedelta(seconds=5) # response.set_cookie(‘my_cookie‘,md5.encrypt(user),expires=deadline) # response.set_cookie(‘my_cookie‘,md5.encrypt(user),max_age=5) # 设置cookie response.set_cookie(‘my_cookie‘,user) return response else: return render(request,‘login.html‘,{‘msg‘:"用户名或密码错误"}) ‘‘‘ ‘‘‘ # login.html ... <form action="/login/" method="POST"> {% csrf_token %} <input type="text" name="user"> <input type="text" name="pwd"> <input type="submit" value="提交"><span style="color: red;">{{ msg }}</span> </form> ... # index.html ... <h1>{{ user }}</h1> ... ‘‘‘ ‘‘‘ # md5.py def encrypt(pwd): import hashlib obj = hashlib.md5() obj.update(pwd.encode(‘utf-8‘)) data = obj.hexdigest() return data if __name__ == ‘__main__‘: print(encrypt(‘123‘)) ‘‘‘ 3.session 是保存在服务器端的键值对 {k:v} 依赖cookie Django默认支持Session,并且默认是将Session数据存储在数据库中,即:django_session 表中。 更多参考:http://www.cnblogs.com/wupeiqi/articles/5246483.html 生成随机字符串,并将其当做cookie发送给客户端 服务端设置随机字符串作为key,自己设置一些{}:request.session[‘my_session_key‘] = user - 设置session request.session[‘yyy‘] = user return redirect(‘/index/‘) - 获取session # 装饰器 def auth(func): def inner(request,*args,**kwargs): ck = request.session.get(‘yyy‘) if not ck: return redirect(‘/login/‘) return func(request,*args,**kwargs) return inner - 清空session request.session.clear() http://www.cnblogs.com/wupeiqi/articles/5246483.html 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,默认修改之后才保存(默认) # 详细代码如下: ‘‘‘ from django.shortcuts import render,HttpResponse,redirect from app01 import models from common import md5 # 判断用户是否登录的装饰器(通过session判断) def auth(func): def inner(request,*args,**kwargs): ck = request.session.get(‘my_session_key‘) if not ck: return redirect(‘/login/‘) return func(request,*args,**kwargs) return inner @auth def index(request): user = request.session.get(‘my_session_key‘) return render(request,‘index.html‘,locals()) @auth def order(request): return render(request,‘order.html‘) # 登出view def logout(request): # 用户登出后清空session request.session.clear() return redirect(‘/index/‘) def login(request): if "GET" == request.method: return render(request,‘login.html‘) else: user = request.POST.get(‘user‘) pwd = request.POST.get(‘pwd‘) obj = models.UserInfo.objects.filter(username=user,password=md5.encrypt(pwd)).first() if obj: # 设置session request.session[‘my_session_key‘] = user return redirect(‘/index/‘) else: return render(request,‘login.html‘,{‘msg‘:"用户名或密码错误"}) ‘‘‘ ‘‘‘ # urls.py from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r‘^admin/‘, admin.site.urls), url(r‘^login/‘, views.login), url(r‘^logout/‘, views.logout), url(r‘^index/‘, views.index), url(r‘^order/‘, views.order), ] ‘‘‘ ‘‘‘ # login.html ... <form action="/login/" method="POST"> {% csrf_token %} <input type="text" name="user"> <input type="text" name="pwd"> <input type="submit" value="提交"><span style="color: red;">{{ msg }}</span> </form> ... # index.html ... <h1>{{ user }}</h1> ... # order.html ... <body> <h1>欢迎登录:{{ request.session.my_session_key }}</h1> <a href="/logout/">注销</a> </body> ... ‘‘‘ 4.csrf 跨站请求伪造 <form action="/login/" method="POST"> {% csrf_token %} <input type="text" name="user"> <input type="text" name="pwd"> <input type="submit" value="提交"><span style="color: red;">{{ msg }}</span> </form> {% csrf_token %} 在浏览器里默认就是一个隐藏的input标签,如下所示: <form action="/login/" method="POST"> <input type=‘hidden‘ name=‘csrfmiddlewaretoken‘ value=‘T2Ub1TacecIsEsKJvoUvB3xNSwrEGT0NajwGeO6y58mp1IseYVLL3FBnXtOT3WgW‘ /> <input type="text" name="user"> <input type="text" name="pwd"> <input type="submit" value="提交"><span style="color: red;"></span> </form> 而 {{ csrf_token }} 这个就是这个隐藏标签的value值 跨站请求的漏洞: <form method="POST" action="http://www.icbc.com.cn/icbc/"> <input type="text" name="from" style="display: none;" value="A的卡号"> <input type="text" name="to" style="display: none;" value="黑客的卡号"> <input type="text" name="money" style="display: none;" value="1000000000"> <input type="submit" name="" value="点我"> </form> {% csrf_token %} # 首先不提交 csrf_token 的情况:报错403,CSRF verification failed. Request aborted. <form id="my_form" action="/login/" method="POST"> <input type="text" name="user"> <input type="email" name="email"> <button onclick="ajaxSubmit()">Ajax提交</button> </form> <script src="{% static "js/bootstrap.min.js" %}"></script> <script> function ajaxSubmit() { $.ajax({ url:‘/show/‘, type:‘POST‘, data:{ ‘user‘:$(‘#my_form input[name="user"]‘).val(), ‘email‘:$(‘#my_form input[name="email"]‘).val() }, success:function (data) { console.log(data); } }) } </script> # 注意一点: # 如果form表单不写action,则默认提交到当前页面 ajax提交csrf_token的几种方式: # 方式1 <form id="my_form" action="/show/" method="post"> {% csrf_token %} <input type="text" name="user"> <input type="email" name="email"> <button onclick="ajaxSubmit()">Ajax提交</button> </form> <script src="{% static "js/bootstrap.min.js" %}"></script> <script> function ajaxSubmit() { $.ajax({ url:‘/show/‘, type:‘POST‘, data:{ ‘user‘:$(‘#my_form input[name="user"]‘).val(), ‘email‘:$(‘#my_form input[name="email"]‘).val(), ‘csrfmiddlewaretoken‘:$(‘input[name="csrfmiddlewaretoken"]‘).val() }, success:function (data) { console.log(data) } }) } </script> # 方式2 只能写在模板里 <body> <form id="my_form" action="/show/" method="post"> {% csrf_token %} <input type="text" name="user"> <input type="email" name="email"> <button onclick="ajaxSubmit()">Ajax提交</button> </form> <script src="{% static "js/bootstrap.min.js" %}"></script> <script> function ajaxSubmit() { $.ajaxSetup({ data: {‘csrfmiddlewaretoken‘:‘{{ csrf_token }}‘} }); $.ajax({ url:‘/show/‘, type:‘POST‘, data:{ ‘user‘:$(‘#my_form input[name="user"]‘).val(), ‘email‘:$(‘#my_form input[name="email"]‘).val() }, success:function (data) { {# do something...#} } }) } </script> </body> # 后端得到的数据: 类型:<class ‘django.http.request.QueryDict‘> 数据:<QueryDict: {‘csrfmiddlewaretoken‘: [‘raZNrc77aQn7cr5Wr6gtTgOaTdNWZKF0HmAfN6kqlGzmyrr4Dw7DUcSVQ6ZHcFoQ‘], ‘email‘: [‘[email protected] om‘], ‘user‘: [‘borui‘]}> # 方式3 只能写在模板里 <form id="my_form" action="/show/" method="post"> {% csrf_token %} <input type="text" name="user"> <input type="email" name="email"> <button onclick="ajaxSubmit()">Ajax提交</button> </form> <script src="{% static "js/bootstrap.min.js" %}"></script> <script> function ajaxSubmit() { $.ajax({ url:‘/show/‘, type:‘POST‘, data:{ ‘user‘:$(‘#my_form input[name="user"]‘).val(), ‘email‘:$(‘#my_form input[name="email"]‘).val(), ‘csrfmiddlewaretoken‘:"{{ csrf_token }}" }, success:function (data) { {# do something...#} } }) } </script> 这种方法,循环form表单,把很多input值拿出来组成字典, 然而实际上POST请求最后是需要转换成字符串放到请求体中发给后端的,实际上的字符串如下: ‘csrfmiddlewaretoken=ouyWxV86TJWMttyLwzRkORIcqXjInlDREG9oTPlp4z81PtUTIZIuPNMXnQvtAgmH&user=love&email=love%40qq.com‘ 所以,如果ajax里的data字段如果写成一个字典,那么就需要一个转成字符串的过程; 如果直接写成字符串,也是可以的; $(‘#my_form‘).serialize() 这个方法就可以把form表单里所有的值(包含隐藏的csrf标签)拼接成一个字符串; # 方法4: <form id="my_form" action="/show/" method="post"> {% csrf_token %} <input type="text" name="user"> <input type="email" name="email"> <button onclick="ajaxSubmit()">Ajax提交</button> </form> <script src="{% static "js/bootstrap.min.js" %}"></script> <script> function ajaxSubmit() { $.ajax({ url:‘/show/‘, type:‘POST‘, data:$(‘#my_form‘).serialize(), success:function (data) { console.log(data) } }) } </script> ‘‘‘ 以上4中方法都是把csrf_token放入 请求体 里传递给后端 ‘‘‘ # 方法5 把csrftoken对应的值方到 请求头 里,传递给后端,这样也可以通过csrf验证 首先引入 jquery.cookie.js 插件 然后通过 $.cookie(‘csrftoken‘) 则可以获取到csrftoken对应的值 这种方法,是把csrftoken对应的值放到请求头里,必须按照这个格式:headers:{‘X-CSRFToken‘: $.cookie(‘csrftoken‘)} 这种情况,请求体的内容可以随便写; <form id="my_form" action="/show/" method="post"> {% csrf_token %} <input type="text" name="user"> <input type="email" name="email"> <button onclick="ajaxSubmit()">Ajax提交</button> </form> <script src="{% static "js/jquery-3.2.1.min.js" %}"></script> <script src="{% static "js/jquery.cookie.js" %}"></script> <script src="{% static "js/bootstrap.js" %}"></script> <script> function ajaxSubmit() { $.ajax({ url:‘/show/‘, type:‘POST‘, data:{‘k1‘:‘v1‘,‘k2‘:‘v2‘}, headers:{‘X-CSRFToken‘: $.cookie(‘csrftoken‘)}, success:function (data) { console.log(data) } }) } </script> 总结: 基于ajax提交form表单,发送csrf验证的方式里 最常用的就是 data:$(‘#my_form‘).serialize() 和 headers:{‘X-CSRFToken‘: $.cookie(‘csrftoken‘)} 另外: 关于csrf有两个装饰器:from django.views.decorators.csrf import csrf_exempt,csrf_protect ‘django.middleware.csrf.CsrfViewMiddleware‘, # 开启则表示全站都使用csrf验证,而csrf_exempt这个装饰器则表示哪些view可以不使用csrf # 如果不开启,则表示全站都不使用csrf验证,而csrf_protect这个装饰器则表示哪些view可以使用csrf
# 自定义分页模块 request.path_info
时间: 2024-10-07 05:30:00