Ajax以及crsf的校验

JSON

注意:json必须是双引号,不能是单引号,否则会报错。如:{“name":"json","sex":"男"}

 

 Ajax

 本质:是一种利用现有技术的新方法。具有局部刷新,异步请求的优点

Ajax的语法:

$('#btn').click(function () {
    $.ajax({
        url:'',//请求url,不写的话,默认是当前页面
        type:'POST', //请求方式,默认是get
        //data:提交给后端的数据
        data:{i1:$('#d1').val(),i2:$('#d2').val()},
        //回调函数
        success:function (data) {
            $('#d3').val(data)
            {#alert(typeof(data))#}
        }
    })
})

了解前后端传输数据的格式:

1、from表单

from表单的默认编码是application/x-www-form-urlencoded格式,django后端会将urlencoded格式的数据自动解析封装到request.POST对象中,

如果编码设置为multipart/form-data,Django后端会将键值对封装在request.POST对象中,文件解析封装在request.FILES对象中。

 

 

 注意:from表单是无法发送json数据的

2、Ajax

ajax默认也是application/x-www-form-urlencoded编码.  参数contentType: 'application/json',将编码格式转化为json格式。

ajax发送文件,需要利用内置FormData()对象,然后将键值对对象,文件对象添加到FormData对象中,将FormData对象发给后端,

Django后端识别到FormData对象,会自动将里面键值对对象解析封装给request.POST,里面的文件数据解析封装给request.FILES对象。

注意 :注意编码格式跟数据格式要保持一致

           Django后端是不会自动帮你处理json数据,需要自己通过request.body来获取二进制的json数据,再用json模块序列化

   发送文件需要将两个参数设置为false,分别是:processData: false, contentType: false,

//ajax发送文件  
$('#btn').on('click',function () { //新建FormData对象 let formdataobj=new FormData(); //添加键值对 formdataobj.append('username',$('#d1').val()) formdataobj.append('password',$('#d2').val())
//添加文件对象 formdataobj.append('file',$('#d3')[0].files[0]) $.ajax({ url:'', type:'post', data:formdataobj, //禁止使用任何编码 processData: false, //禁止浏览器对你数据进行处理 contentType: false, success:function (args) { } }) })

 Django内置的serializers

#导入serializers模块
from django.core import serializers
#拿到user表中所有的用户
obj=models.User.objects.all()
#调用模块下的方法进行序列化,第一个参数表示序列化后的数据类型
 ret=serializers.serialize('json',obj)

自定义分页器的封装方法及使用

一般自定义的插件或者接口,都会存放在django项目下新建的utils目录下

class Pagination(object):
    def __init__(self, current_page, all_count, per_page_num=2, pager_count=11):
        """
        封装分页相关数据
        :param current_page: 当前页
        :param all_count:    数据库中的数据总条数
        :param per_page_num: 每页显示的数据条数
        :param pager_count:  最多显示的页码个数
        """
        try:
            current_page = int(current_page)
        except Exception as e:
            current_page = 1

        if current_page < 1:
            current_page = 1

        self.current_page = current_page

        self.all_count = all_count
        self.per_page_num = per_page_num

        # 总页码
        all_pager, tmp = divmod(all_count, per_page_num)
        if tmp:
            all_pager += 1
        self.all_pager = all_pager

        self.pager_count = pager_count
        self.pager_count_half = int((pager_count - 1) / 2)
    #@property装饰器的方法,就是把方法变成属性使用
    @property
    def start(self):
        return (self.current_page - 1) * self.per_page_num

    @property
    def end(self):
        return self.current_page * self.per_page_num

    def page_html(self):
        # 如果总页码 < 11个:
        if self.all_pager <= self.pager_count:
            pager_start = 1
            pager_end = self.all_pager + 1
        # 总页码  > 11
        else:
            # 当前页如果<=页面上最多显示11/2个页码
            if self.current_page <= self.pager_count_half:
                pager_start = 1
                pager_end = self.pager_count + 1

            # 当前页大于5
            else:
                # 页码翻到最后
                if (self.current_page + self.pager_count_half) > self.all_pager:
                    pager_end = self.all_pager + 1
                    pager_start = self.all_pager - self.pager_count + 1
                else:
                    pager_start = self.current_page - self.pager_count_half
                    pager_end = self.current_page + self.pager_count_half + 1

        page_html_list = []
        # 添加前面的nav和ul标签
        page_html_list.append('''
                    <nav aria-label='Page navigation>'
                    <ul class='pagination'>
                ''')
        first_page = '<li><a href="?page=%s">首页</a></li>' % (1)
        page_html_list.append(first_page)

        if self.current_page <= 1:
            prev_page = '<li class="disabled"><a href="#">上一页</a></li>'
        else:
            prev_page = '<li><a href="?page=%s">上一页</a></li>' % (self.current_page - 1,)

        page_html_list.append(prev_page)

        for i in range(pager_start, pager_end):
            if i == self.current_page:
                temp = '<li class="active"><a href="?page=%s">%s</a></li>' % (i, i,)
            else:
                temp = '<li><a href="?page=%s">%s</a></li>' % (i, i,)
            page_html_list.append(temp)

        if self.current_page >= self.all_pager:
            next_page = '<li class="disabled"><a href="#">下一页</a></li>'
        else:
            next_page = '<li><a href="?page=%s">下一页</a></li>' % (self.current_page + 1,)
        page_html_list.append(next_page)

        last_page = '<li><a href="?page=%s">尾页</a></li>' % (self.all_pager,)
        page_html_list.append(last_page)
        # 尾部添加标签
        page_html_list.append('''
                                           </nav>
                                           </ul>
                                       ''')
        return ''.join(page_html_list)
自定义分页器

后端引用:

def page(request):
    #获取第一页
    current_page=request.GET.get('page',1)
    
    book_obj=models.Book.objects.all()
    #获取总页数
    book_all=book_obj.count()
    #获取分页器对象
    pagination=Pagination(all_count=book_all,current_page=current_page,per_page_num=10)
    #调用分页器对象中的start、end属性,就查询结果进行切片处理
    book_list=book_obj[pagination.start:pagination.end]
    return render(request,'page.html',locals())

前端引用:

{% for i in book_list %}
      <p>{{ i.name }}</p>
{% endfor %}
//取消对pagination.page_html属性中的html代码的转义
{{ pagination.page_html|safe }}

 csrf_token校验

form表单的校验

 //直接在form标签后面添加  {% csrf_token %}
  <form method="post" action="">
        {% csrf_token %}
        <p><input  type="hidden"></p>
        <p>username:<input type="text" name="id"></p>
        <p>Password:<input type="password" name="passwd"></p>
        <p><input type="submit" value="提交" id="btn"></p>
    </form>

Ajax的三种校验方法(注意:ajax不能是form表单内的按钮点击事件,否则无法校验)

1、获取隐藏的input标签中的csrfmiddlewaretoken值,放置在data中发送。

2、利用模板的快捷书写方法(前后端分离的时候,就用不了)

$('#b1').click(function () {
      $.ajax({
           url:'',
           type:'post',
           data:{'id':$('#d1').val(),'passwd':$('#d2').val(),
           //第一种方法:获取隐藏的input标签中的csrfmiddlewaretoken值,放置在data中发送。
             "csrfmiddlewaretoken":$('[name=csrfmiddlewaretoken]').val()
           //  第二种方法:利用模版的快捷书写方法
              "csrfmiddlewaretoken":'{{ csrf_token }}'
                },
           success:function () {
              }
          })
 })

3、通用方法,引用一个js文件,具体使用方法:在html页面引用该js文件

function getCookie(name) {
    var cookieValue = null;
    if (document.cookie && document.cookie !== '') {
        var cookies = document.cookie.split(';');
        for (var i = 0; i < cookies.length; i++) {
            var cookie = jQuery.trim(cookies[i]);
            // Does this cookie string begin with the name we want?
            if (cookie.substring(0, name.length + 1) === (name + '=')) {
                cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                break;
            }
        }
    }
    return cookieValue;
}
var csrftoken = getCookie('csrftoken');

function csrfSafeMethod(method) {
  // these HTTP methods do not require CSRF protection
  return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}

$.ajaxSetup({
  beforeSend: function (xhr, settings) {
    if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
      xhr.setRequestHeader("X-CSRFToken", csrftoken);
    }
  }
});

csrf相关的装饰器

from django.views.decorators.csrf import csrf_exempt,csrf_protect
'''
csrf_exempt: 不需要校验
csrf_protect: 需要校验
总结:这两个装饰器在CBV中使用中
    csrf_protect在CBV的三个方法中是通用的
    csrf_exempt: 只有加在dispatch方法上才有用
'''

 

posted @ 2020-10-11 20:57  NQ31  阅读(95)  评论(0编辑  收藏  举报