一、全自動(較爲經常使用)css
Django ORM會自動幫你建立第三張表只需定義兩張表類使用多對多外鍵鏈接html
class Book(models.Model): name = models.CharField(max_length=32) price = models.CharField(max_length=32) authors = models.ManyToManyField(to='Author') # 會自動幫你建立第三張表 class Author(models.Model): name = models.CharField(max_length=32) addr = models.CharField(max_length=32)
好處:第三張表自動建立前端
不足:第三張表沒法擴展額外的字段git
二、存手動github
第三張表本身手動建立,外鍵鏈接兩張表,能夠擴展額外的字段,可是不能用ORM查詢語句,無正向反向的概念了ajax
class Book(models.Model): name = models.CharField(max_length=32) price = models.CharField(max_length=32) class Author(models.Model): name = models.CharField(max_length=32) addr = models.CharField(max_length=32) class Book_Author(models.Model): book = models.ForeignKey(to='Book') author = models.ForeignKey(to='Author') create_time = models.DateField(auto_now_add=True)
好處:第三張表能夠擴展額外的字段數據庫
不足之處:ORM查詢的時候不方便django
三、半自動(推薦使用)json
手動建立第三張表,在關聯的兩張表中都建立多對多的外鍵,使得能夠擴展任意的字段bootstrap
class Book(models.Model): name = models.CharField(max_length=32) price = models.CharField(max_length=32) # 多對多的外鍵字段須要再指定兩個關鍵字參數through='第三張表',through_fields = ('本表名','另外一種關係表名') authors = models.ManyToManyField(to="Author", through="Book_Author", through_fields=('book', 'author')) class Author(models.Model): name = models.CharField(max_length=32) addr = models.CharField(max_length=32) # 多對多的外鍵字段須要再指定兩個關鍵字參數through='第三張表',through_fields = ('本表名','另外一種關係表名')
# books = models.ManyToManyField(to="Book", through='Book_Author', through_fields=('author', 'book')) # 不須要兩張表同時寫
class Book_Author(models.Model): book = models.ForeignKey(to='Book') author = models.ForeignKey(to='Author') create_time = models.DateField(auto_now_add=True)
好處:第三張表能夠擴展任意的額外字段,還能夠經過ORM的正反向查詢
不足:沒法使用,add,set,remove,clear方法對第三張表操做
Ajax不是一門新的語言,它其實就是基於js寫的一個功能模塊
異步提交,局部刷新(最大的優勢):不加載整個頁面的狀況下,能夠跟服務器交換數據並更新部分網頁內容,在不知不覺的過程當中完成了請求響應過程
應用:在用戶輸入關鍵字的時候,會自動去數據庫中進行查詢和進行校驗操做,最後返回出結果,整個過程頁面沒有刷新,只是刷新局部的位置
// ajax基本語法 $.ajax({ // 1.到底朝哪一個後端提交數據 url:'', // 控制數據的提交路徑 有三種寫法 跟form表單的action屬性一致 // 2.指定當前請求方式 type:'post', // 3.提交的數據 data:{'i1':$('#i1').val(),'i2':$('#i2').val()}, // 4.ajax是異步提交 因此須要給一個回調函數來處理返回的結果 success:function (data) { // data就是異步提交的返回結果 // 將異步回調的結果經過DOM操做渲染到第三個input框中 $('#i3').val(data) } })
application/urlencoded
前端代碼以 username=jason&password=123格式展現
Django後端會針對該種格式的數據會自動解析打包到request.POST中
multipart/form-data
django後端針對符合urlencoded編碼格式數據(普通鍵值對)仍是統一解析到request.POST中
後端會針對formdata數據格式的文件數據會自動解析到request.FILES中
application/json
先後的數據交互編碼格式必定要同樣,是json格式的發送要進行轉碼
Django後端針對json格式數據,不會作任何的處理,而是放進request.body中須要本身手動進行轉換,先解碼,再反序列化(json.loads可以自動解碼並序列化)
json_bytes = request.body json_dict = json.loads(json_bytes) # 拿到真實的字典數據
提交數據兩種方式:form表單和Ajax
一、默認是urlencoded編碼格式傳輸數據
前端以username=Jason&password=123展現,Django後端會自動解析打包到request.POST中,而針對文件數據只能獲取文件名,並不能真正獲取文件數據
二、能夠修改成formdata數據格式
指定enctype="multipart/form-data"
<form action="" method="post" enctype="multipart/form-data">
django後端針對符合urlencoded編碼格式數據(普通鍵值對)仍是統一解析到request.POST中,會針對formdata數據格式的文件數據會自動解析到request.FILES中
Ajax默認也是urlencoded編碼格式,也能夠修改提交數據格式爲json數據格式
能夠修改提交的數據格式爲:contentType:'application/json'
$('#d1').on('click', function () { $.ajax({ url:'', type:'post', // 修改contentType參數 contentType:'application/json', // 改爲json格式的傳輸,須要將數據序列化成json格式 data:JSON.stringify({'username':'tank','password':123}), success:function (data) { alert(data) } }) })
後端須要本身處理數據,將拿到的數據解碼再反序列化才能拿到真實字典數據
# 本身處理json格式數據 json_bytes = request.body # 先解碼 # json_str = json_bytes.decode('utf-8') # 再反序列化 # json_dict = json.loads(json_str) # 擴展 json.loads可以自動解碼並序列化 json_dict = json.loads(json_bytes) print(json_dict,type(json_dict))
內置對象FormData:既能夠發普通鍵值對數據也能夠發文件數據
Ajax發送文件數據須要藉助於內置對象
一、首先須要生成一個內置對象
var myFormData = new FormData
二、向生成的對象中添加數據
三、發送Ajax請求
// 須要先生成一個內置對象 var myformdata = new FormData(); // 向內置對象中添加普通鍵值對 myformdata.append('username','jason'); // 向對象中添加文件數據,獲取input中傳入的文件 myformdata.append('myfile',$('#d1')[0].files[0]); // 發送Ajax請求 $.ajax({ url:'', type:'post', data:myformdata, // 發送formdata數據須要指定兩個關鍵性參數爲false processData:false, // 讓瀏覽器不要對數據作任何操做 contentType:false, // 不要使用任何編碼,FormData自帶編碼格式Django能識別該對象 success:function (data) { alert(data) }
Django內置的序列功能借助 serializers 模塊,能夠序列化對象
之前咱們將後端將數據傳遞給前端經過json序列化
from app01 import models import json def xlh(request): book_query = models.Book.objects.all() book_list = [] for book_obj in book_query: book_list.append({ 'name': book_obj.name, 'price': book_obj.price }) res = json.dumps(book_list) return render(request, 'xlh.html', locals())
咱們可使用Django內置的序列化功能模塊 serializers ,直接序列化,展現的結果更加多將類名,主鍵都能拿到
from django.core import serializers def xlh(request): book_query = models.Book.objects.all() res = serializers.serialize('json', book_query) return HttpResponse(res) # [{"model": "app01.book", "pk": 1, "fields": {"name": "jason", "price": "123"}}]
咱們以前學過的批量插入數據方式經過for循環再利用create方法,可是每次都要走數據庫,效率很低
def insert_data(request): for i in range(1,501): models.Book.objects.create(name='第%s本書'%i) book_query = models.Book.objects.all() return render(request, 'insert.html', locals()) # 每次循環一次都須要去數據庫插入一條,500條大約須要一分鐘
咱們能夠經過先將數據添加到一個列表中再使用 bulk_create 方法插入數據,這樣就只會走一次數據庫,效率很高
def insert_data(request): book_list = [] for i in range(1,9999): book_list.append(models.Book(name='新添加的第%s書'%i)) models.Book.objects.bulk_create(book_list) # 批量插入數據 book_query = models.Book.objects.all() return render(request, 'insert.html', locals()) # 效率很高,大約1秒插入9999條數據
一、先引用分頁器組件,封裝好的類,存入本地文件夾中
class Pagination(object): def __init__(self, current_page, all_count, per_page_num=10, pager_count=11): """ 封裝分頁相關數據 :param current_page: 當前頁 :param all_count: 數據庫中的數據總條數 :param per_page_num: 每頁顯示的數據條數 :param pager_count: 最多顯示的頁碼個數 用法: queryset = model.objects.all() page_obj = Pagination(current_page,all_count) page_data = queryset[page_obj.start:page_obj.end] 獲取數據用page_data而再也不使用原始的queryset 獲取前端分頁樣式用page_obj.page_html """ 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 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)
後端代碼:
# 獲取當前頁碼,默認爲1 current_page = request.GET.get('page', 1) # 獲取總頁數 all_count = book_queryset.count() # 生成一個自定義分頁器類對象 page_obj=Pagination(current_page=current_page,all_count=all_count,pager_count=9) # 針對真實的queryset數據進行切片操做 page_queryset = book_queryset[page_obj.start:page_obj.end] return render(request,'ab_bc.html',locals())
前端代碼:
{{ page_obj.page_html|safe }}
一、首先須要從sweetalert 鏈接找到Bootstrap-sweetalert包,將包下載到本地
咱們只須要使用dist文件中的 js 和 css 文件
二、從sweetalert forBootstrap中找到須要使用的樣式,引用其代碼
咱們以刪除二次確認爲例:
後端代碼:
from django.http import JsonResponse import time def show_user(request): """ 先後端若是是經過ajax進行交互 那麼交互的媒介通常狀況下都是一個字典 """ if request.method == 'POST': # 模仿刪除等待效果 time.sleep(3) # 定義一個字典,經過Ajax傳給後端的data back_dic = {"code":1000,'msg':''} # 拿到須要刪除的數據id delete_id = request.POST.get('delete_id') # 將數據刪除 models.Userinfo.objects.filter(pk=delete_id).delete() back_dic['msg'] = '刪除成功,準備跑路!!!' # 以json數據格式將字典返回給前端Ajax中的data return JsonResponse(back_dic) user_queryset = models.Userinfo.objects.all() return render(request,'show_user.html',locals())
前端代碼:
首先須要引入sweetalert文件中的css和js文件
{% load static %} <link rel="stylesheet" href="{% static 'dist/sweetalert.css' %}"> <script src="{% static 'dist/sweetalert.min.js' %}"></script> {# 刪除中文文字寬度不夠,找到文字標籤修改大小#} <style> div.sweet-alert h2 { padding-top: 10px; } </style>
調用sweetalert中樣式代碼,加以修改
<script> // 給刪除按鈕綁定點擊事件 $('.cancel').click(function () { // 定義變量指代某一條數據 var $aEle = $(this); // 引用sweetalert中的刪除樣式代碼 swal({ title: "你肯定要刪嗎?", text: "你若是刪了,你可要準備跑路啊!", type: "warning", showCancelButton: true, confirmButtonClass: "btn-danger", confirmButtonText: "是的,老子就要刪!", cancelButtonText: "惹不起惹不起!", closeOnConfirm: false, closeOnCancel: false, showLoaderOnConfirm: true }, function (isConfirm) { if (isConfirm) { // 發送ajax請求 $.ajax({ url:'', type:'post', data:{'delete_id':$aEle.attr("data_id")}, success:function (data) { // 回調函數會自動將二進制的json格式數據 解碼並反序列成js中的數據類型 if (data.code == 1000){ swal("刪了!", "你準備跑路吧!", "success"); // 方式1 刪除後自動刷新網頁 // window.location.reload() // 方式2 DOM操做動態修改,將刪除的那條數據移除 $aEle.parent().parent().remove() // 將標籤直接移除 }else{ swal('發生了未知的錯誤', "error"); } } }); } else { swal("慫筆", "你成功的刷新我對你的認知", "error"); } }); }) </script>