Django (二)

一. cookie

a. 简单应用

def login(request):
    if request.method=="GET":
        return render(request,"login.html")
    else:
        name = request.POST.get("name")
        password = request.POST.get("password")
        if name == "alex" and password == "123":
            obj = redirect("/classes/")
            obj.set_cookie("ticket","123456",max_age=10)
            return obj
        else:
            return redirect("/login/")



def classes(request):
    sk = request.COOKIES
    print(sk)
    if not sk:
        return redirect("/login/")
View Code 

b. 过期时间的两种格式

方式一:
obj.set_cookie("ticket","123456",max_age=10)

方式二:
import datetime
from datetime import timedelta     #时间的加减
ct = datetime.datetime.utcnow()   #获取当前日期
v= timedelta(seconds=10)   #10秒
value = ct + v

obj.set_cookie("ticket","123456",expires=value)

c. 限制路径

obj.set_cookie("ticket","123456",max_age=10,path="/")   #所有路径都可以访问

obj.set_cookie("ticket","123456",max_age=10,path="/class")   #只有class访问

d. cookie签名

#加
obj.set_signed_cookie("ticket","123456",salt="abc")

#解
sk = request.get_signed_cookie("ticket",salt="abc")

二. session

流程:客户登录网址,验证成功后,服务端生成一个随机字符串和随机字符串对应的键值,然后把随机字符串通过cookie发送给客户端
	 客户端拿着随机字符串通过cookir再次登陆,服务端拿着随机字符串和保存在本地的数据对应,以确定用户的登录状态
Cookie是什么?
    保存在客户端浏览器上的键值对
Session是什么?
    保存在服务端的数据(本质是键值对)
    {
        “aaaaa":{'id':1,'name':'于浩',email='xxxx'}
        "bbbbb":{'id':2,'name':'陈涛',email='0000'}
    }
    应用:依赖cookie
    作用:保持会话(Web网站)
    好处:敏感信息不会直接给客户端
    
    梳理:
        1. 保存在服务端的数据(本质是键值对)
        2. 配置文件中:
            - 存储位置
            - 超时时间、每次刷新更新时间
View Code

a. 简单示例

用户访问http://127.0.0.1:8000/login/
urlpatterns = [

    url(r'^index/', views.index),
    url(r'^login/', views.login),
]
urls.py
def login(request):
    if request.method == 'GET':
        return render(request,'login.html')
    else:
        u = request.POST.get('user')
        p = request.POST.get('pwd')
        obj = models.UserAdmin.objects.filter(username=u,password=p).first()
        if obj:
            # 1. 生成随机字符串
            # 2. 通过cookie发送给客户端
            # 3. 服务端保存
            # {
            #   随机字符串1: {'username':'alex','email':x''...}
            # }
            request.session['username'] = obj.username
            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/')
Views.py
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<form action="/login/" method="POST">
    <input type="text" name="user">
    <input type="text" name="pwd">
    <input type="submit" value="提交">{{ msg }}
</form>


</body>
</html>
login.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

    <h1>index page</h1>

</body>
</html>
index.html

三. cbv

cbv(class-base-view)    基于类的视图
fbv(func-base-view)     基于函数的视图

a. 基本演示

urlpatterns = [
   
    url(r'^login.html$', views.Login.as_view()),
]
urls.py
from django.views import View

class Login(View):

    def dispatch(self, request, *args, **kwargs):
        print('before')
        obj = super(Login,self).dispatch(request,*args,**kwargs)
        print("after")
        return obj

    def get(self,request):
        return render(request,"login.html")

    def post(self,request):
        print(request.POST)

        return HttpResponse("Login.post")
View.py

四. 分页 

a. django分页

#浏览器访问
http://127.0.0.1:8000/index.html/?page=9
urlpatterns = [
 
    #django分页
    url(r'^index', views.index),
]
urls.py
#django 分页
from django.core.paginator import Paginator,Page,PageNotAnInteger,EmptyPage
def index(request):
    current_page = request.GET.get("page")
    user_list = models.User_info.objects.all()
    paginator = Paginator(user_list,10)  #每页显示10条

    """
    # count:    数据总个数
    # num_pages:总页数
    # page_range:总页数的索引范围,如: (1,10),(1,200)
    # page:     page对象
    """
    try:
        posts = paginator.page(current_page)   #当前页
    except PageNotAnInteger as e:   #http://127.0.0.1:8000/index.html/?page=qqq 处理这种异常
        posts = paginator.page(1)
    except EmptyPage as e:  #http://127.0.0.1:8000/index.html/?page=-10  捕获这种异常
        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})
View.py
<!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 %}

        {% for num in posts.paginator.page_range %}
            <a href="/index.html/?page={{ num }}">{{ num }}</a>
        {% endfor %}

        {% if posts.has_next %}
            <a href="/index.html/?page={{ posts.next_page_number }}">下一页</a>
        {% endif %}
    </div>

</body>
</html>
index.html

b. 自定义分页

#浏览器访问
http://127.0.0.1:8000/custom/?page=6
urlpatterns = [

    #自定义分页
    url(r'^custom/', views.custom),
]
urls.py
from utils.pager import PageInfo
#自定义分页
def custom(request):

    #总页数
    all_count = models.User_info.objects.all().count()

    #用户当前想要访问的页码
    current_page = request.GET.get("page")
    page_info = PageInfo(current_page,all_count,10,"/custom",11)

    user_list = models.User_info.objects.all()[page_info.start():page_info.end()]

    return render(request,"custom.html",{"user_list":user_list,"page_info":page_info})
View.py
class PageInfo(object):

    def __init__(self,current_page,all_count,per_page,base_url,show_page=11):

        #如果传值错误进入第一页
        try:
            self.current_page = int(current_page)
        except Exception as e:
            self.current_page = 1
        self.per_page = per_page            #每页显示的个数


        a,b = divmod(all_count,per_page)    #页数  余数
        if b:
            a = a + 1
        self.all_page = a                   #总页码
        self.show_page = show_page
        self.base_url = base_url

    def start(self):
        # 1  0: 10
        # 2  10:20
        # 3  20:30
        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)

        if self.all_page < self.show_page:
            begin = 1
            stop = self.all_page + 1
        else:
            if self.current_page < half:
                begin = 1
                stop = self.show_page + 1
            else:
                if self.current_page + half > self.all_page:
                    begin = self.all_page - 10 +1
                    stop = self.all_page + 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='/custom/?page=%s'>%s</a></li>"%(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_page:
            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)
utils/pager.py
from django.db import models

# Create your models here.


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")
models.py
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="/static/plugins/bootstrap-3.3.7-dist/css/bootstrap.css" />
</head>
<body>

    {% for row in user_list %}
        <li>{{ row.name }}</li>
    {% endfor %}


    <nav aria-label="Page navigation">
      <ul class="pagination">
        {{ page_info.pager |safe }}

      </ul>
    </nav>
</body>
</html>
custom.html
class PageInfo(object):

    def __init__(self,current_page,all_count,per_page,base_url,show_page=11):

        #如果传值错误进入第一页
        try:
            self.current_page = int(current_page)
        except Exception as e:
            self.current_page = 1
        self.per_page = per_page            #每页显示的个数


        a,b = divmod(all_count,per_page)    #页数  余数
        if b:
            a = a + 1
        self.all_page = a                   #总页码
        self.show_page = show_page
        self.base_url = base_url

    def start(self):
        # 1  0: 10
        # 2  10:20
        # 3  20:30
        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)

        if self.all_page < self.show_page:
            begin = 1
            stop = self.all_page + 1
        else:
            if self.current_page < half:
                begin = 1
                stop = self.show_page + 1
            else:
                if self.current_page + half > self.all_page:
                    begin = self.all_page - 10 +1
                    stop = self.all_page + 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_page:
            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)
修改后 utils/pager.py

五. XSS

对用户提交的数据验证

1.以安全的字符串显示出来,没有样式
2.加safe,以安全的方式显示,过滤关键字

六. CSRF

CSRF(Cross-site request forgery)跨站请求伪造,通常缩写为CSRF或者XSRF,是一种对网站的恶意利用。尽管听起来像跨站脚本(XSS)
    但它与XSS非常不同,XSS利用站点内的信任用户,而CSRF则通过伪装来自受信任用户的请求来利用受信任的网站。

自己理解:csrf_token防止从别的网站向自己网站发post请求, 客户来访问网站,网站会向客户发送随机字符串,然后客户带随机字符串发送post请求
        只有带随机字符串来,网站才认,一般是post请求才要求带随机字符串,其它网站第一次来不会带随机字符串。

a. django开启csrf 

MIDDLEWARE = [
    'django.middleware.csrf.CsrfViewMiddleware',
]

b.HTML中使用

{% csrf_token %}       #只要写上{% csrf_token %} 会有一个隐藏的input随机字符串,在cookie也有一个随机的字符串,form表单提交数据时,一般会使用
{{ csrf_token }}       #生成随机的字符串

c.django中设置防跨站请求伪造功能有分为全局和局部

#局部

from django.views.decorators.csrf import csrf_exempt,csrf_protect

@csrf_protect   settings中没有设置全局中间件,为当前函数强制设置防跨站请求伪造功能。
@csrf_exempt    settings中设置了全局中间件,取消当前函数防跨站请求伪造功能。
#fbv

@csrf_protect
def func(object):
    pass

#cbv

from django.views import View
from django.utils.decorators import method_decorator

@method_decorator(csrf_exempt,name="dispatch")
class foo(View)
    pass
fbv和cbv应用装饰器  
#方式一 类上加装饰器:

def wrapper(func):
    def inner(*args,**kwargs):
        return func(*args,**kwargs)
    return inner

@method_decorator(wrapper,name="get")
@method_decorator(wrapper,name="post")
class foo(View):

    def get(self,request):
        pass

    def post(self,request):
        pass



#方式二 类上“dispatch”加装饰器:

def wrapper(func):
    def inner(*args,**kwargs):
        return func(*args,**kwargs)
    return inner

@method_decorator(wrapper,name="dispatch")
class foo(View):

    def dispatch(self,request,*args,**kwargs):
        return xxx

    def get(self,request):
        pass

    def post(self,request):
        pass


#方式三 方法上加装饰器:

def wrapper(func):
    def inner(*args,**kwargs):
        return func(*args,**kwargs)
    return inner

class foo(View):


    @method_decorator(wrapper)
    def get(self,request):
        pass

    def post(self,request):
        pass
cbv应用其它装饰器

d. Ajax提交数据 携带CSRF 

1. 通过获取隐藏的input标签中的字符串 放置在data中发送  js代码可以和html在不同文件中(推荐使用)

{% csrf_token %}

$.ajax({
	data:{"csrfmiddlewaretoken":$("[name='csrfmiddlewaretoken']").val()
});
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form method="POST" action="/csrf1.html">
        {% csrf_token %}
        <input id="user" type="text" name="user"/>
        <a onclick="submitForm();">Ajax提交</a>
    </form>

    <script src="/static/jquery-1.12.4.js"></script>
    <script>
        function submitForm() {
            var csrf = $('input[name="csrfmiddlewaretoken"]').val();
            var user = $("#user").val();
            $.ajax({
                url:'/csrf1.html',
                type:'POST',
                data:{"user":user,"csrfmiddlewaretoken":csrf},
                success:function (arg) {
                    console.log(arg);
                }

            })
        }
    </script>



</body>
</html>
csrf1.html
urlpatterns = [

    url(r'^csrf1.html', views.csrf1),
]
urls.py
def csrf1(request):

    if request.method == 'GET':
        return render(request,'csrf1.html')
    else:
        return HttpResponse('ok')
View.py

2. 通过获取返回的cookie中的字符串 放置在请求头中发送 

通过在console中 document.cookie可以获取csrftoken=JPv1gIdrBiAlK2RCrgFs0OKwsncPXvwPfMhEWIVzMdMFymIayiuGu2GkBAu57moL
但需要切割字符串,通过引入jquery.cookie.js对cookie操作,使用$.cookie("csrftoken")

<script src="/static/jquery.cookie.js"></script>

$.ajax({
	headers:{"X-CSRFToken":$.cookie('csrftoken')},
})
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form method="POST" action="/csrf1.html">
        {% csrf_token %}
        <input id="user" type="text" name="user"/>
        <a onclick="submitForm();">Ajax提交</a>
    </form>

    <script src="/static/jquery-1.12.4.js"></script>
    <script src="/static/jquery.cookie.js"></script>
    <script>
        function submitForm() {
            var token = $.cookie("csrftoken");
            var user = $("#user").val();
            $.ajax({
                url:'/csrf1.html',
                type:'POST',
                headers:{"X-CSRFToken":token},
                data:{"user":user},
                success:function (arg) {
                    console.log(arg);
                }

            })
        }
    </script>





</body>
</html>
csrf1.html

3. 直接在ajax里发送

模版页面第一次render渲染时生成,js代码需要和html在一个文件中。如果js代码在其它文件中,是不会渲染的

$.ajaxSetup({
    data: {csrfmiddlewaretoken: '{{ csrf_token }}' },
});
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form method="POST" action="/csrf1.html">

        <input id="user" type="text" name="user"/>
        <a onclick="submitForm();">Ajax提交</a>
    </form>

    <script src="/static/jquery-3.2.1.js"></script>
    <script>
        function submitForm() {

            var user = $("#user").val();
            $.ajax({
                url:'/index/',
                type:'POST',
                data:{"user":user,"csrfmiddlewaretoken":"{{ csrf_token }}"},
                success:function (arg) {
                    console.log(arg);
                }

            })
        }
    </script>



</body>
</html>
csrf1.html

七. 中间件

#django 中的中间件(middleware),在django中,中间件其实就是一个类,在请求到来和结束后,django会根据自己的规则在合适的时机执行中间件中相应的方法。

a. 注册中间件

在django项目的settings模块中,有一个 MIDDLEWARE_CLASSES 变量,其中每一个元素就是一个中间件,如下图。

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',
    "md.M1",
    "md.M2",
]

  

  

  

 

  

 

 

 

  

 

 

  

  

原文地址:https://www.cnblogs.com/golangav/p/7077090.html