1. 程式人生 > 其它 >Django06_choices引數,多對多關係建立方式,ajax

Django06_choices引數,多對多關係建立方式,ajax

1.choices引數(資料庫欄位設計常見)

生活中針對某些欄位可以列舉完所有可能性欄位,我們該如何儲存。例如學歷,部門等可以例舉出所有情況,如果儲存字串很明顯佔用儲存資源,一個比較好的方式是,儲存一個數字,然後在數字與現實名稱之間做個對映。choices引數就是如此做的。

class User(models.Model):
    username = models.CharField(max_length=32)
    age = models.IntegerField()
    # 性別
    gender_choices = (
        (1,'男'),
        (2,'女'),
        (3,'其他'),
    )
    gender = models.IntegerField(choices=gender_choices)
    
    score_choices = (
        ('A','優秀'),
        ('B','良好'),
        ('C','及格'),
        ('D','不合格'),
    )
    # 保證欄位型別跟列舉出來的元組第一個資料型別一致即可
    score = models.CharField(choices=score_choices,null=True)
    """
    該gender欄位存的還是數字 但是如果存的數字在上面元組列舉的範圍之內
    那麼可以非常輕鬆的獲取到數字對應的真正的內容
    
    1.gender欄位存的數字不在上述元祖列舉的範圍內容
    2.如果在 如何獲取對應的中文資訊
    """

    from app01 import models
    # models.User.objects.create(username='jason',age=18,gender=1)
    # models.User.objects.create(username='egon',age=85,gender=2)
    # models.User.objects.create(username='tank',age=40,gender=3)
    # 存的時候 沒有列舉出來的數字也能存(範圍還是按照欄位型別決定)
    # models.User.objects.create(username='tony',age=45,gender=4)

    # 取
    # user_obj = models.User.objects.filter(pk=1).first()
    # print(user_obj.gender)
    # 只要是choices引數的欄位 如果你想要獲取對應資訊 固定寫法 get_欄位名_display()
    # print(user_obj.get_gender_display())

    user_obj = models.User.objects.filter(pk=4).first()
    # 如果沒有對應關係 那麼欄位是什麼還是展示什麼,比較智慧
    print(user_obj.get_gender_display())  # 4

2.多對多三種建立方式

2.1全自動

class Book(models.Model):
    name = models.CharField(max_length=32)
    authors = models.ManyToManyField(to='Author')
	class Author(models.Model):
    name = models.CharField(max_length=32)
	"""
	優點:程式碼不需要你寫 非常的方便 還支援orm提供操作第三張關係表的方法...
	不足之處:第三張關係表的擴充套件性極差(沒有辦法額外新增欄位...)
	"""

2.2純手動

class Book(models.Model):
    name = models.CharField(max_length=32)
    
class Author(models.Model):
    name = models.CharField(max_length=32)
  
class Book2Author(models.Model):
    book_id = models.ForeignKey(to='Book')
    author_id = models.ForeignKey(to='Author')
'''
優點:第三張表完全取決於你自己進行額外的擴充套件
不足之處:需要寫的程式碼較多,不能夠再使用orm提供的簡單的方法
不建議你用該方式

2.3半自動

class Book(models.Model):
    name = models.CharField(max_length=32)
    authors = models.ManyToManyField(to='Author',
                                     through='Book2Author',
                                     through_fields=('book','author')
                                     )
class Author(models.Model):
    name = models.CharField(max_length=32)
    # books = models.ManyToManyField(to='Book',
    #                                  through='Book2Author',
    #                                  through_fields=('author','book')
    #                                  )
class Book2Author(models.Model):
    book = models.ForeignKey(to='Book')
    author = models.ForeignKey(to='Author')

"""
through_fields欄位先後順序
    判斷的本質:
        通過第三張表查詢對應的表 需要用到哪個欄位就把哪個欄位放前面
    你也可以簡化判斷
        當前表是誰 就把對應的關聯欄位放前面
        
半自動:可以使用orm的正反向查詢 但是沒法使用add,set,remove,clear這四個方法
"""

總結:你需要掌握的是全自動還是半自動 為了擴充套件性更高 一般採用半自動(寫程式碼要給自己留條後路)
半自動只能查。

3.Ajax

3.1Ajax的特點

非同步提交,區域性重新整理。
例子,百度搜索的時候輸入時候輸入框下方會進行提示,github註冊的時候使用者名稱是否重複實時提示

3.2瀏覽器向伺服器傳送請求的集中方式

方式 方法
瀏覽器位址列直接輸入url回車 GET
a標籤href屬性 GET
form表單 GET/POST
ajax GET/POST

3.3小例子

頁面上有三個input框
在前兩個框中輸入數字 點選按鈕 朝後端傳送ajax請求
後端計算出結果 再返回給前端動態展示的到第三個input框中
(整個過程頁面不準有重新整理,也不能在前端計算)

$('#btn').click(function () {
        // 朝後端傳送ajax請求
        $.ajax({
            // 1.指定朝哪個後端傳送ajax請求
            url:'', // 不寫就是朝當前地址提交
            // 2.請求方式
            type:'post',  // 不指定預設就是get 都是小寫
            // 3.資料
            {#data:{'username':'jason','password':123},#}
            data:{'i1':$('#d1').val(),'i2':$('#d2').val()},
            // 4.回撥函式:當後端給你返回結果的時候會自動觸發 args接受後端的返回結果
            success:function (args) {
                {#alert(args)  // 通過DOM操作動態渲染到第三個input裡面#}
                {#$('#d3').val(args)#}
                console.log(typeof args)

            }
        })
    })

針對後端如果是用HttpResponse返回的資料 回撥函式不會自動幫你反序列化
如果後端直接用的是JsonResponse返回的資料 回撥函式會自動幫你反序列化

HttpResponse解決方式
    1.自己在前端利用JSON.parse()
    2.在ajax裡面配置一個引數

3.4前後端傳輸資料的編碼格式(contentType)

get請求資料就是直接放在url:url?username=jason&password=123
可以朝後端傳送post請求的方式:

form表單,ajax請求

前後端傳輸資料的編碼格式:

urlencoded、formdata、json

我們主要研究post請求資料的編碼格式

3.4.1form表單

預設的資料編碼格式是urlencoded,資料格式:username=jason&password=123,django後端針對符合urlencoded編碼格式的資料都會自動幫你解析封裝到request.POST中

username=jason&password=123 >>> request.POST

如果你把編碼格式改成formdata,那麼針對普通的鍵值對還是解析到request.POST中而將檔案解析到request.FILES中

form表單是沒有辦法傳送json格式資料的

3.4.2ajax

預設的編碼格式也是urlencoded,資料格式:

username=jason&age=20

django後端針對符合urlencoded編碼格式的資料都會自動幫你解析封裝到request.POST中

username=jason&age=20 >>> request.POST

3.5ajax傳送json格式資料

前後端傳輸資料的時候一定要確保編碼格式跟資料真正的格式是一致的,不要騙人家!!!

{"username":"jason","age":25}在request.POST裡面肯定找不到
django針對json格式的資料 不會做任何的處理

request物件方法補充
request.is_ajax()
判斷當前請求是否是ajax請求 返回布林值

<script>
    $('#d1').click(function () {
        $.ajax({
            url:'',
            type:'post',
            data:JSON.stringify({'username':'jason','age':25}),
            contentType:'application/json',  // 指定編碼格式
            success:function () {

            }
        })
    })
</script>
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)

ajax傳送json格式資料需要注意點

1.contentType引數指定成:application/json
2.資料是真正的json格式資料
3.django後端不會幫你處理json格式資料需要你自己去request.body獲取並處理

3.6ajax傳送檔案

ajax傳送檔案需要藉助於js內建物件FormData

<script>
    // 點選按鈕朝後端傳送普通鍵值對和檔案資料
    $('#d4').on('click',function () {
        // 1 需要先利用FormData內建物件
        let formDateObj = new FormData();
        // 2 新增普通的鍵值對
        formDateObj.append('username',$('#d1').val());
        formDateObj.append('password',$('#d2').val());
        // 3 新增檔案物件
        formDateObj.append('myfile',$('#d3')[0].files[0])
        // 4 將物件基於ajax傳送給後端
        $.ajax({
            url:'',
            type:'post',
            data:formDateObj,  // 直接將物件放在data後面即可

            // ajax傳送檔案必須要指定的兩個引數
            contentType:false,  // 不需使用任何編碼 django後端能夠自動識別formdata物件
            processData:false,  // 告訴你的瀏覽器不要對你的資料進行任何處理

            success:function (args) {
            }
        })
    })
</script>
def ab_file(request):
    if request.is_ajax():
        if request.method == 'POST':
            print(request.POST)
            print(request.FILES)
    return render(request,'ab_file.html')

總結:
1.需要利用內建物件FormData
// 2 新增普通的鍵值對
formDateObj.append('username',$('#d1').val());
formDateObj.append('password',$('#d2').val());
// 3 新增檔案物件
formDateObj.append('myfile',$('#d3')[0].files[0])
2.需要指定兩個關鍵性的引數
contentType:false, // 不需使用任何編碼 django後端能夠自動識別formdata物件
processData:false, // 告訴你的瀏覽器不要對你的資料進行任何處理
3.django後端能夠直接識別到formdata物件並且能夠將內部的普通鍵值自動解析並封裝到request.POST中 檔案資料自動解析並封裝到request.FILES中

3.7django自帶的序列化元件

需求:在前端給我獲取到後端使用者表裡面所有的資料 並且要是列表套字典

import json
from django.http import JsonResponse
from django.core import serializers
def ab_ser(request):
    user_queryset = models.User.objects.all()
    # [{},{},{},{},{}]
    # user_list = []
    # for user_obj in user_queryset:
    #     tmp = {
    #         'pk':user_obj.pk,
    #         'username':user_obj.username,
    #         'age':user_obj.age,
    #         'gender':user_obj.get_gender_display()
    #     }
    #     user_list.append(tmp)
    # return JsonResponse(user_list,safe=False)
    # return render(request,'ab_ser.html',locals())

    # 序列化
    res = serializers.serialize('json',user_queryset)
    """會自動幫你將資料變成json格式的字串 並且內部非常的全面"""
    return HttpResponse(res)
"""
[
 {"pk": 1, "username": "jason", "age": 25, "gender": "male"}, 
 {"pk": 2, "username": "egon", "age": 31, "gender": "female"},
 {"pk": 3, "username": "kevin", "age": 32, "gender": "others"}, 
 {"pk": 4, "username": "tank", "age": 40, "gender": 4}
 ]
前後端分離的專案
    作為後端開發的你只需要寫程式碼將資料處理好
    能夠序列化返回給前端即可 
        再寫一個介面文件 告訴前端每個欄位代表的意思即可
        
        
[
{   "model": "app01.user", 
    "pk": 1, 
    "fields": {"username": "jason", "age": 25, "gender": 1}}, 
    
{   "model": "app01.user", 
    "pk": 2, 
    "fields": {"username": "egon", "age": 31, "gender": 2}}, 
    
{   "model": "app01.user", 
    "pk": 3, 
    "fields": {"username": "kevin", "age": 32, "gender": 3}},
     
{   "model": "app01.user", 
    "pk": 4, 
    "fields": {"username": "tank", "age": 40, "gender": 4}}
]
"""
### 3.8ajax結合sweetalert
sweetalert請自行百度
自己要學會如何拷貝
學會基於別人的基礎之上做修改
研究各個引數表示的意思 然後找葫蘆畫瓢
```js
<script>
    $('.del').on('click',function () {
        // 先將當前標籤物件儲存起來
        let currentBtn = $(this);
        // 二次確認彈框
        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:'/delete/user/' + currentBtn.attr('delete_id'),  // 1 傳遞主鍵值方式1#}
                    url:'/delete/user/',  // 2 放在請求體裡面
                    type:'post',
                    data:{'delete_id':currentBtn.attr('delete_id')},
                    success:function (args) {  // args = {'code':'','msg':''}
                        // 判斷響應狀態碼 然後做不同的處理
                        if(args.code === 1000){
                            swal("刪了!", args.msg, "success");
                            // 1.lowb版本 直接重新整理當前頁面
                            {#window.location.reload()#}
                            // 2.利用DOM操作 動態重新整理
                            currentBtn.parent().parent().remove()
                        }else{
                            swal('完了','出現了位置的錯誤','info')
                        }
                    }

                })

          } else {
            swal("慫逼", "不要說我認識你", "error");
          }
        });
    })
</script>