CSIC_716_2020110【Django入门---多对多表关系的三种创建方式、Ajax、自定义分页器、删除的二次弹窗确认】

多对多表关系的建立方式(以图书表和作者表为例)

多对多表关系的创建有三种方式:自动创建、手动创建、半自动创建

前文中已经介绍了多对多的全自动创建方式,但是创建的第三张表中只有两个外键字段,因为是该表是django自动生成的,故没办法在第三张表中增加其余字段

本文介绍剩余的两种:

纯手动创建以及半自动创建

纯手动创建

特点:多对多的第三张关系表是自己手动创建的,相较于全自动创建而言,在关系表中除外键外还可以添加任意字段。

不足:在跨表查询的时候比较麻烦,不可以使用django orm提供的便利方法

class Book(models.Model):
    title = models.CharField(max_length= 32 )
    price = models.DecimalField(max_digits=8, max_places=2)


class Author(models.Model):
    name = models.CharField(max_length = 32)
    age = models.IntegerField()
 

class Book2Author(models.Model):
    book = models.ForeignKey(to = 'Book')
    author = models.ForeignKey(to = 'Author')
    remark = models.CharField(max_length = 32)

  

半自动创建

外键建在book表中  注意外键括号内参数的区别

class Book(models.Model):
    title = models.CharField(max_length= 32 )
    price = models.DecimalField(max_digits=8, max_places=2)
    authors = models.ManyToMany(to='Author', through=‘Book2Author’,through_fields=('book','author'))


class Author(models.Model):
    name = models.CharField(max_length = 32)
    age = models.IntegerField()
 

class Book2Author(models.Model):
    book = models.ForeignKey(to='Book')
    author = models.ForeignKey(to ='Author')
    remark = models.CharField(max_length = 32)

  外键建在author中

class Book(models.Model):
    title = models.CharField(max_length= 32 )
    price = models.DecimalField(max_digits=8, max_places=2)
    

class Author(models.Model):
    name = models.CharField(max_length = 32)
    age = models.IntegerField()
    books= models.ManyToMany(to='Book', through=‘Book2Author’,through_fields=('author','book'))
 

class Book2Author(models.Model):
    book = models.ForeignKey(to='Book')
    author = models.ForeignKey(to ='Author')
    remark = models.CharField(max_length = 32)

  优点:扩展性强,可以在关系表总增加任意字段,并且还可以使用orm提供的跨表查询的方法,推荐

缺点: orm提供的多对多外键的增删改查没办法使用了即无法使用 add、set、remove、clear四个方法无法使用。

 

 

Ajax

ajax的特点:异步提交,局部刷新。Ajax是通过js语言写的一个功能模块,本文学习的是通过jQuery封装好的ajax模块

目前本人已知的与后端交互的方式有如下四种:

1、浏览器窗口中直接写网址:请求方式GET;

2、<a>标签中的 href后面填写url :请求方式GET;

3、form表单    :    GET和POST请求都可以;

4、Ajax:   GET和POST请求都可以;

 

Ajax的基本语法结构:

四个步骤:向哪个地址提交、以什么请求方式、提交什么内容、返回的结果如何处理

$.ajax({
    urls:' ',   #可以填具体的url,也可以填地址的后缀,也可以不填默认提交到当前
    type:' ',     # type的类型有get和post
    data:{ },     # 必须要保证是个字典的样式传
    success:function(data):{     #data为后端处理后传到前端的值
            代码块
            代码块
        }
})

  

 

form表单默认的是以urlencoded的编码格式传输数据,后端接收到数据后会先存入request.body,然后再将键值对数据自动存到request.POST中;当表单中有普通键值对和文件时,就需要修改enctype属性,以formdata编码格式传输数据,后端接收到数据后会先存入request.body,然后再将普通键值对存到request.POST中,将文件数据存入request.FILES中。

Ajax也是默认以urlencoded方式传输数据,Ajax中有一个contentType属性可以指定编码方式,除了urlencoded外还支持application/json,但是如果明确了contentType是application/json时,data后面的数据就一定要是json类型的数据,可以借助Javascript中自带的序列化方法JSON.stringify,后端接收到的数据以二进制形式存放在request.body中,后端可以通过json.loads(request.body)取值,loads可以直接将符合json格式的二进制数据反序列化,举例如下:

$.ajax({
    urls:' ' ,   
    type:' ' ,

    contentType:'application/json' ,
    data:JSON.stringify({ }) ,  

    success:function(data):{     
            代码块
        }
}) 

  

需要注意的是,如果前端以json形式发到后端,后端收到值后,会存放到request.body中,取j值直接从request.body中取,取出来的是一组二进制的json数据。

这时候按照套路应该先解码再反序列化。但是在后端,json.loads(二进制json)会直接先解码再反序列化

 

)

 

 Ajax发送文件数据

这里需要使用JavaScript的内置对象FormData,它既可以存键值对也能存文件。

$(#d1).on('click', function(){   //给id为d1的按钮绑定click方法
  var myFormData = new FormData();
  myFormData.append( 'key', 'value' ) ; //普通键值写入的方法
  myFormData.append( 'key', '$(#d1)[0]files[0]');
//数据组织完了,下面开始Ajax操作
  $.ajax({
    url:' ',
    type:'post' ,
    data:myFormData,
//发送FormData对象需要指定下面两个关键的参数
    processData:false,  //让浏览器不要动数据
    contentType: false,  //不使用编码格式,因为FormData自带django能识别的编码格式
    success:function(data){
        代码块
      }
  })
})

  

 

 django内置的序列化功能     后期会介绍drf

 

在线JSON校验格式化工具    BeJSON

序列化模块  serializers

from django.core import   serializers

res = serializers.serialize('json' , queryset)  // 第一个参数是明确序列化成json格式,第二个参数是提供一个queryset对象

 

 

 批量向数据库中插入数据的方式

 使用 models.Book.objects.bulk_create(对象列表)

def bulk_create(request):
    list_obj = []
    #通过for循环生成对象,再将对象append进list_obj中
    for i in range(1000):
         list_obj.append(models.Book(title = '第%s本书'% i))
     models.Book.objects.bulk_create(list_obj)
     book_queryset = models.Book.objects.all()
     return ....

  

 自定义分页器

 略

 

  1 class Pagination(object):
  2     def __init__(self, current_page, all_count, per_page_num=10, 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         all_pager, tmp = divmod(all_count, per_page_num)
 32         if tmp:
 33             all_pager += 1
 34         self.all_pager = all_pager
 35 
 36         self.pager_count = pager_count
 37         self.pager_count_half = int((pager_count - 1) / 2)
 38 
 39     @property
 40     def start(self):
 41         return (self.current_page - 1) * self.per_page_num
 42 
 43     @property
 44     def end(self):
 45         return self.current_page * self.per_page_num
 46 
 47     def page_html(self):
 48         # 如果总页码 < 11个:
 49         if self.all_pager <= self.pager_count:
 50             pager_start = 1
 51             pager_end = self.all_pager + 1
 52         # 总页码  > 11
 53         else:
 54             # 当前页如果<=页面上最多显示11/2个页码
 55             if self.current_page <= self.pager_count_half:
 56                 pager_start = 1
 57                 pager_end = self.pager_count + 1
 58 
 59             # 当前页大于5
 60             else:
 61                 # 页码翻到最后
 62                 if (self.current_page + self.pager_count_half) > self.all_pager:
 63                     pager_end = self.all_pager + 1
 64                     pager_start = self.all_pager - self.pager_count + 1
 65                 else:
 66                     pager_start = self.current_page - self.pager_count_half
 67                     pager_end = self.current_page + self.pager_count_half + 1
 68 
 69         page_html_list = []
 70         # 添加前面的nav和ul标签
 71         page_html_list.append('''
 72                     <nav aria-label='Page navigation>'
 73                     <ul class='pagination'>
 74                 ''')
 75         first_page = '<li><a href="?page=%s">首页</a></li>' % (1)
 76         page_html_list.append(first_page)
 77 
 78         if self.current_page <= 1:
 79             prev_page = '<li class="disabled"><a href="#">上一页</a></li>'
 80         else:
 81             prev_page = '<li><a href="?page=%s">上一页</a></li>' % (self.current_page - 1,)
 82 
 83         page_html_list.append(prev_page)
 84 
 85         for i in range(pager_start, pager_end):
 86             if i == self.current_page:
 87                 temp = '<li class="active"><a href="?page=%s">%s</a></li>' % (i, i,)
 88             else:
 89                 temp = '<li><a href="?page=%s">%s</a></li>' % (i, i,)
 90             page_html_list.append(temp)
 91 
 92         if self.current_page >= self.all_pager:
 93             next_page = '<li class="disabled"><a href="#">下一页</a></li>'
 94         else:
 95             next_page = '<li><a href="?page=%s">下一页</a></li>' % (self.current_page + 1,)
 96         page_html_list.append(next_page)
 97 
 98         last_page = '<li><a href="?page=%s">尾页</a></li>' % (self.all_pager,)
 99         page_html_list.append(last_page)
100         # 尾部添加标签
101         page_html_list.append('''
102                                            </nav>
103                                            </ul>
104                                        ''')
105         return ''.join(page_html_list)
自定义分页器引用文件

 

 current_page = request.GET.get('page', 1)
    all_count = book_queryset.count()
    # 1 现生成一个自定义分页器类对象
    page_obj = Pagination(current_page=current_page,all_count=all_count,pager_count=9)
    # 2 针对真实的queryset数据进行切片操作
    page_queryset = book_queryset[page_obj.start:page_obj.end]
自定义分页器后端

 

{% for book_obj in page_queryset %}
    <p>{{ book_obj.title }}</p>
{% endfor %}
{{ page_obj.page_html|safe }}
自定义分页器前端

 

 

Ajax结合Sweetalert实现删除二次确认

 代码

 SweetAlert for Bootstrap

 

 

posted @ 2020-01-10 16:54  HEU葉孤城  阅读(191)  评论(0编辑  收藏  举报