­

Django与Ajax

  • 2019 年 10 月 3 日
  • 筆記

一. MTV与MVC

  MTV模型(django): M:models.py    T: templates    V: views

  MVC模型: M:模型层(models.py)     T: 视图层(views.py)    V: 控制层(Controller)

  本质: Django的MTV也是MVC

二. 多对多的三种创建方式

  1. 第一种Django orm自动帮我们创建

class Book(models.Model)      name = models.CharField(max_length=32)      authors = models.ManyToManyField(to='Author')    class Author(mofels.Model)      name = models.CharField(max_length=32)  

  创建这张表时,会自动告诉Django帮我们进行第三张表的创建,创建的名称为app01_Book_Author

  2. 手动创建第三张表(用foreignkey创建时,mysql会自动在字段名后面加_id,那我们在创建的时候在模型层就没有必要在字段名后面手动添加_id)

class Book(models.Model)      name = models.CharField(max_length=32)      class Author(mofels.Model)      name = models.CharField(max_length=32)    class Book2Author(models.Model)      book = models.ForeignKey(to='Book')      author = models.ForeignKey(to='Author')      info = models.CharField(max_length=32)  

  纯手动创建第三张表,好处在于可以给第三张表中添加其他字段,如果在orm中创建表时,不能再新加其他其他字段,纯手动创建的表不支持反向查询例子奉上,基于双下划綫

  基于对象的反向查询:

  3. 半自动创建第三张表

class Book(models.Model)      name = models.CharField(max_length=32)      # 第三种创建表的方式      authors = models.ManyToManyField(to='Author', through='Book2Author', through_fields=('book', 'author')      class Author(mofels.Model)      name = models.CharField(max_length=32)    class Book2Author(models.Model)      book = models.ForeignKey(to='Book')      author = models.ForeignKey(to='Author')      info = models.CharField(max_length=32)  

  通过through来告诉orm   book与author已经创建第三张表book2author, book与author已经创建book2author这张表,orm不用再创建了, thorugh_fields表示的是虽然orm知道book与author创建关系,但是纯手动创建的表可以再添加字段,也就是说orm不知道第三张表中哪个字段与那个字段有关联,通过through_fields可以清楚的知道哪张表与哪张表有关系,比如想从第三张表中查出第一张表,通过什么能查到呢,在本例子中是通过book找到Book这张表,那么through_fields的第一个参数就是book,第二个参数表示book这张表与哪张表有关系,就写那张表名小写.

  这种方法既可以支持在第三张表中添加字段,也可以支持反向查询(可扩展性强)

  查询第三张表中新加的字段

三. 前后端传输数据编码格式contentType

  urlencoded:

    对应的数据格式: name=jason&password=123

    后端获取数据: request.POST

    ps: django会将urlencoded编码的数据解析自动放在request.POST中

  formdata:

    form表单传输文件的编码格式

    后端获取文件格式的数据:request.FILES

    后端获取普通键值对数据: request.POST

    Django后端针对只要是符合urlencoded编码格式的数据都会自动解析到request.POST中

 

四. ajax

  1. 前端向后端发送请求的方式:

    浏览器中手动输入网址:  get请求

    a标签的href属性: get请求

    form表单: get/post请求(默认为get请求)

    ajax: get/post请求

  2. ajaxt特点: 异步提交, 局部刷新

    ajax不是新的语言,而是一种现有标准的新方法,基于JavaScript

    同步交互: 客户端发出一个请求之后,需要等待服务器响应结束,才能发出第二个请求; (form表单提交)

    异步交互: 客户端发出一个请求之后,无需等待服务器响应结束,就可以发出第二个请求

    ajax最大的优点是在不重新加载整个页面的情况下,可以与服务器交换数据并更新部分网页内容.(这一特点给用户的感受是在不知不觉中完成请求和响应过程)

    ajax基本语法: 提交的地址, 提交的方式,提交的数据, 回调函数

$('#d1').click(function () {              $.ajax({                  // 提交的地址                  url: '/index/',                  // 提交的方式                  type:'post',                  // 提交的数据                     data:{'name': 'bgon', 'password':'123'},                  // 回调函数                  success:function(data){     // data接收的就是异步提交返回的结果                      alert(data)                  }          }}      })  

  4. ajax默认传输数据的编码格式也是urlencoded

  5. 前后端进行数据交互时,前端传输什么格式的数据,后端也要传输什么样的格式在前端传输数据时先声明下数据的编码格式,在前端传输json格式的数据时,后端会将json格式的数据保存在request.body里面,这是一个字符类型的数据,我们可以将他进行解码,然后进行反序列化出原来的样式.

$('#d1').click(function () {              $.ajax({                  // 提交的地址                  url: '/index/',                  // 提交的方式                  type:'post',                   // 传输格式                   contentType:'application/json',                  // 提交的数据                     data:json.stringify{'name': 'bgon', 'password':'123'},                  // 回调函数                  success:function(data){     // data接收的就是异步提交返回的结果                      alert(data)                  }          }}      })  

  ajax传输文件

$('#d1').click(function(){      let formdata = new FormData();   // 实例化产生对象          // FormData对象不仅可以传输文件,还可以传输普通的键值对        formdata.append('name', 'jason');   // 固定这么写          // 获取input框存放的文件,先用jQuery查找存储文件的标签,利用jQuery对象转换成js对象,利用原生js对象的方法.files[0]来获取到标签内部存储的文件对象          // $('#il')[0].files[0]   // 先将jquery对象转换成原生的js对象.然后就支持.files,当前input框中所有所有的文件          formdata.append('myfile , $('#il')[0].files[0]);          $.ajax({              url:'',              type:'post',              data: formdata,              // ajax发送文件需要修改两个固定的参数              processData: false,   // 告诉浏览器不要处理我的数据              contentType: false,    // 不要用任何的编码,我就用formdata自带的编码格式              // 回调函数              success: function (data) {                  alert          }       })  });        ajax传输文件需要借助内置对象FormDate  

  form表单与ajax异同点:

    1. form表单不支持异步提交局部刷新

    2. form表单不支持传输json格式的数据

    3. form表单与ajax默认传输数据的编码格式都是urlencoded

  特别提醒: 在用ajax传输数据时,一定要注意传输的类型与编码格式一致

五. 批量插入数据

批量插入数据  	l = []      for i in range(10000):          l.append(models.Book2(name='第%s本书'%i))      models.Book2.objects.bulk_create(l)  # 批量插入数据

六. 分页器

后端:    book_list = models.Book2.objects.all()    # 数据总条数    all_count = book_list.count()    # 当前页    current_page = request.GET.get('page',1)    # 示例一个分页器对象    page_obj = my_page.Pagination(current_page=current_page,all_count=all_count)    # 对总数据进行切片    page_queryset = book_list[page_obj.start:page_obj.end]    前端:    {{ page_obj.page_html|safe }}  # 帮你渲染的是带有bootstrap样式的分页器  

  分页器组件

  1 class Pagination(object):    2     def __init__(self,current_page,all_count,per_page_num=2,pager_count=11):    3         """    4         封装分页相关数据    5         :param current_page: 当前页    6         :param all_count:    数据库中的数据总条数    7         :param per_page_num: 每页显示的数据条数    8         :param pager_count:  最多显示的页码个数    9   10         用法:   11         queryset = model.objects.all()   12         page_obj = Pagination(current_page,all_count)   13         page_data = queryset[page_obj.start:page_obj.end]   14         获取数据用page_data而不再使用原始的queryset   15         获取前端分页样式用page_obj.page_html   16         """   17         try:   18             current_page = int(current_page)   19         except Exception as e:   20             current_page = 1   21   22         if current_page <1:   23             current_page = 1   24   25         self.current_page = current_page   26   27         self.all_count = all_count   28         self.per_page_num = per_page_num   29   30   31         # 总页码   32         all_pager, tmp = divmod(all_count, per_page_num)   33         if tmp:   34             all_pager += 1   35         self.all_pager = all_pager   36   37         self.pager_count = pager_count   38         self.pager_count_half = int((pager_count - 1) / 2)   39   40     @property   41     def start(self):   42         return (self.current_page - 1) * self.per_page_num   43   44     @property   45     def end(self):   46         return self.current_page * self.per_page_num   47   48     def page_html(self):   49         # 如果总页码 < 11个:   50         if self.all_pager <= self.pager_count:   51             pager_start = 1   52             pager_end = self.all_pager + 1   53         # 总页码  > 11   54         else:   55             # 当前页如果<=页面上最多显示11/2个页码   56             if self.current_page <= self.pager_count_half:   57                 pager_start = 1   58                 pager_end = self.pager_count + 1   59   60             # 当前页大于5   61             else:   62                 # 页码翻到最后   63                 if (self.current_page + self.pager_count_half) > self.all_pager:   64                     pager_end = self.all_pager + 1   65                     pager_start = self.all_pager - self.pager_count + 1   66                 else:   67                     pager_start = self.current_page - self.pager_count_half   68                     pager_end = self.current_page + self.pager_count_half + 1   69   70         page_html_list = []   71         # 添加前面的nav和ul标签   72         page_html_list.append('''   73                     <nav aria-label='Page navigation>'   74                     <ul class='pagination'>   75                 ''')   76         first_page = '<li><a href="?page=%s">首页</a></li>' % (1)   77         page_html_list.append(first_page)   78   79         if self.current_page <= 1:   80             prev_page = '<li class="disabled"><a href="#">上一页</a></li>'   81         else:   82             prev_page = '<li><a href="?page=%s">上一页</a></li>' % (self.current_page - 1,)   83   84         page_html_list.append(prev_page)   85   86         for i in range(pager_start, pager_end):   87             if i == self.current_page:   88                 temp = '<li class="active"><a href="?page=%s">%s</a></li>' % (i, i,)   89             else:   90                 temp = '<li><a href="?page=%s">%s</a></li>' % (i, i,)   91             page_html_list.append(temp)   92   93         if self.current_page >= self.all_pager:   94             next_page = '<li class="disabled"><a href="#">下一页</a></li>'   95         else:   96             next_page = '<li><a href="?page=%s">下一页</a></li>' % (self.current_page + 1,)   97         page_html_list.append(next_page)   98   99         last_page = '<li><a href="?page=%s">尾页</a></li>' % (self.all_pager,)  100         page_html_list.append(last_page)  101         # 尾部添加标签  102         page_html_list.append('''  103                                            </nav>  104                                            </ul>  105                                        ''')  106         return ''.join(page_html_list)

分页器组件

  当我们在使用分页器的时候可以在app01下建立一个utils的文件夹用来存放分页器组件代码