Django基础04-day19

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Django基础04-day19相关的知识,希望对你有一定的参考价值。

写在前面



 上课第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

  

 

以上是关于Django基础04-day19的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Django Summernote 中显示编程片段的代码块?

Django基础—— 19.Form

19 01 11 javascript ?????????????????????(???????????????) ??????????????????????????????(代码片段

django.core.exceptions.ImproperlyConfigured: Requested setting DEFAULT_INDEX_TABLESPACE的解决办法(转)(代码片段

django.core.exceptions.ImproperlyConfigured: Requested setting DEFAULT_INDEX_TABLESPACE的解决办法(转)(代码片段

Django安装及配置 -- 2019-08-11 19:29:16