django

  • 2020 年 11 月 25 日
  • 筆記

1 AJAX

1 ajax基本語法

test.html
<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
  {#一定要記得導包,然後再settings.py中配置static文件夾路徑#}
   <script src="/static/jquery-3.3.1/jquery-3.3.1.min.js"></script>
   <script src="/static/jquery-3.3.1/jquery-3.3.1.js"></script>
   <title>Title</title>
</head>
<body>
<input type="text" id="d1">
+
<input type="text" id="d2">
=
<input type="text" id="d3">

<p>
   <button id="btn">點我</button>
</p>


<script>
   // 先給id="btn"的按鈕綁定一個點擊事件
   $('#btn').click(function () {
       $.ajax({
           // 1.指定朝那個後端發送ajax請求
           url: '/index/', //不寫就是朝當前地址提交

           // 2.請求方式
           type: 'post', //不寫默認就是get

           // 3.數據
           data: {
               'i1': $('#d1').val(),  //$('#d1'):找到元素id為d1的元素,val()拿到元素的value值
               'i2': $('#d2').val()
          },

           // 4.回調函數:當後端給你返回結果的時候會自動觸發,args接受後端的返回結果,就算返回的是個頁面也是回調函數接收
           success: function (args) {
               // 通過dom操作動態渲染到第三個input框中
               $('#d3').val(args) //如果val()裡帶參數會把參數渲染到頁面
          }
      })
  })
</script>


</body>

{#如果後端用的是HttpResponse返回的數據,回調函數不會自動幫你反序列化,結果還是字元串#}
{#但是,如果後端直接用的是JsonResponse返回的數據,回調函數會自動幫你反序列化將字元串變為對象#}
   
   
{#HttpResponse解決方法#}
{#   1.自己在前端利用JSON.parse()#}
{#   2.在ajax里配置一個參數ContentType: true#}

</html>

view.py

def ab_ajax(request):
   if request.method == 'POST':
       i1 = request.POST.get('i1')
       i2 = request.POST.get('i2')
       res = int(i1) + int(i2)
  return HttpResponse(res)
   return render(request, 'test.html')

 

2 前後端傳輸數據的編碼格式

# 1 我們主要研究post請求數據的編碼格式
"""
get請求數據就是直接放在url後面的,如:
url?username=xpj&password=123
"""

# 2 前後端傳輸數據的三種格式
"""
1 urlencoded: form表單提交數據格式

2 multipart/formdata: 針對文件格式,封裝到request.FILES里

3 json
"""

# 3 可以朝後端發送post請求的方式
"""
1 form表單
默認的數據編碼格式是urlencoded
數據格式:username=xpj&password=123
django後端針對urlencoded編碼格式的數據會自動幫你封裝到request.POST中

如果你把編碼格式改為formdata,那麼針對普通的鍵值對還是解析到request.POST中,而針對文件會解析到request.FILFES中

form表單是沒有辦法傳輸json個是數據的

2 ajax請求
默認的數據編碼格式是urlencoded
數據格式:username=xpj&password=123
django後端針對urlencoded編碼格式的數據會自動幫你封裝到request.POST中
"""

 

3 ajax發送json格式數據

'''
前後端傳輸數據的時候一定要確保編碼格式跟數據格式是一致的

如果傳輸的是json格式的數據request.post里是找不到的

request.is_ajax(),判斷當前請求是否是ajax請求,返回bool值

django針對json格式的數據不會做任何處理,需要自己處理

解決方法:
1.json_bytes = request.body
json_str = json_bytes.decode('utf-8')
json_dict = json.loads(json_str)

2.json_dict = json.loads(json_bytes)

'''

#1 ajax改變發送的編碼格式
$.ajax({
   '''''
  cententType: 'application/json', //指定編碼格式
  ''''''
})

 

4 ajax發送文件

'''
ajax發送文件需要藉助js內置對象FormData
'''
<script>
       $('#d4').on('click', function (){
           
           // 1 需要先利用FormData內置對象生成一個對象
           let formdata_obj = new FormData()
           
           // 2 添加普通的鍵值對
           formdata_obj.append('username', $('#d1').val());
           formdata_obj.append('password', $('#d2').val());
           
           // 3 添加文件對象,$('#d3')是jquery對象, $('#d3')[0]轉成原生js對象標籤對象, $('#d3')[0].files[0]拿到用戶傳進來的文件對象
           formdata_obj.append('myfile', $('#d3')[0].files[0])
           
           // 4 將對象基於ajax發送給後端
           $.ajax({
               url: '',
               type: 'post',
               data: formdata_obj, //直接將對象放在data後面即可

               //ajax發送文件必須要指定的兩個參數
               contentType: false, // 不需要使用任何編碼,django後端能夠自動識別formdata對象
               processData: false, // 告訴你的遊覽器不要對你的數據進行任何處理
               
               success: function (args){
                   alert(1)
              }
          })
      })
</script>

 

5 ajax結合sweetalert實現二次確認

<p>
   <button class="del" delete_id="{{ user_obj.pk }}"></button>
</p>

<script>
   $('.del').on('click', function (){
       alert($(this).attr('delete_id'))    //this拿到的是當前標籤.attr拿到標籤的屬性
  })
</script>

 

6 批量插入數據

# bulk_create()

book_list = []
for i in range(100000):
   book_obj = models.Book.objects.all()
   book_list.append(book_list)
models.Book.objects.bulk_create(book_list)
return render(request, 'ab_pl.html', locals())

 

2 auth

1 auth常用方法

# 1 對比用戶名和密碼是否正確
user_obj = auth.authenticate(request, username=username, password=password) # 括弧內必須同時傳入request, 用戶名和密碼
print(user_obj) # 用戶對象 jason
print(user_obj.username) # jason
print(user_obj.password) # 密文

# 2 保存用戶狀態
auth.login(request, user_obj) # 執行了該方法,你可以在任何地方通過request.user獲取當前登錄的對象

# 3 判斷當前用戶是否登錄
request.user.is_authenticated()

# 4 獲取當前登錄用戶
request.user

# 5 校驗用戶是否登錄裝飾器
from django.contrib.auth.decorators import login_required

# 局部配置,用戶沒有登錄會跳轉到login頁面
@login_required(login_url='/login/')

# 全局配置,可以在settings.py里配置LOGIN_URL = '/login/'
@required_login()

# 局部>全局,全局的好處在於無需重複寫程式碼但是只能跳轉一個頁面,局部的好處在於不同的試圖函數在沒有用戶登錄的情況下可以跳轉到不同的頁面

# 6 密碼處理
# 比對原密碼
request.user.check_password(old_password)

# 修改密碼
request.user.set_password(new_password) # 僅僅是在修改對象的屬性
request.user.save() # 這一步才是真正操作資料庫

# 7 註銷
auth.logout(request)

# 8 註冊
# 直接創建但是密碼不加密
User.objects.create(username=username, password=password)

# 創建普通用戶密碼能加密
User.objects.create_user(username=username, password=password)

# 創建超級用戶
User.objects.create_superuser(username=username, email='[email protected]', password=password)

 

2 auth模組表拓展

class UserInfo(AbstractUser):
   """
  如果繼承了AbstractUser
  那麼在執行資料庫遷移命令的時候auth_user表就不會再創建出來了
  UserInfo表中會出現auth_user所有的欄位外加自己拓展的欄位
  """
   phone = models.BigIntegerFeild()
   
   """
  前提:
  1. 必須在auth_user沒有被創建之前繼承
  2. 必須在settings.py里聲明
  AUTH_USER_MODEL = 'app01.UserInfo'
  3. 繼承的類不能出現同名欄位
  """

 

3 orm

1 單表操作

測試腳本

models.py

class User(models.Model):
   name = models.CharField(max_length=32)
   age = models.IntegerField()
   register_time = models.DateTimeField(auto_now_add=True)

   def __str__(self):
       return self.name

test.py

# 去manage.py文件中複製前四行程式碼,粘貼進test.py文件中並寫入兩行程式碼,即可在單個py文件中進行測試

import os

def main():
   os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'djangoProject3.settings')
   # 這兩行是新加入的
   import django
   django.setup()

2 必知必會13條

# 1 create()
models.User.objects.create(name='kerwin', age=24)

# 2 delete()
models.User.objects.filter(pk=2).delete()
(1, {'app01.User': 1}) # 返回剩餘個數

# 3 update()
models.User.objects.filter(pk=1).update(age=18)
1 # 修改成功返回1

# 4 filter()
models.User.objects.filter(pk=1)
<QuerySet [<User: xpj>]> # 拿到的是queryset,不存在返回空

# 5 fisrt()
models.User.objects.filter(pk=1).first()
<User: xpj> # 拿到對象

# 6 get()
models.User.objects.get(pk=1)
<User: xpj> # 拿到的是User對象,但是如果不存在的話會報錯

# 7 values()
models.User.objects.values('name') # 欄位查詢
<QuerySet [{'name': 'xpj'}]> # 列表套字典的queryset

# 8 values_list()
models.User.objects.values_list('name', 'age')
<QuerySet [('xpj', 24)]> # 列表套元組的queryset

# 9 distinct()
models.User.objects.values('name', 'age').distinct()

# 10 order_by()
models.User.objects.order_by('age')
models.User.objects.order_by('-age') # 降序

# 11 count()
models.User.objects.filter(pk=1).count()

# 12 reverser() # 反轉
# 13 exists() # 存在
# 14 exclude() #

3 雙下劃線查詢

#1 年齡大於35歲
models.User.objects.filter(age__gt=35)

#2 年齡小於35歲
models.User.objects.filter(age__lt=35)

#3 年齡大於等於,小於等於35歲
models.User.objects.filter(age__gte=35)
models.User.objects.filter(age__lte=35)

#4 年齡是18,32,40
models.User.objects.filter(age__in=[18,32,40])

#5 年齡是18到40歲之間的
models.User.objects.filter(age__range=[18,40])

 

2 多表操作

1 多表準備

models.py


class Book(models.Model):
   title = models.CharField(max_length=32)
   price = models.DecimalField(max_digits=8, decimal_places=2)
   publish_date = models.DateTimeField(auto_now_add=True)

   publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE)
   authors = models.ManyToManyField(to='Author')


class Publish(models.Model):
   name = models.CharField(max_length=32)
   addr = models.CharField(max_length=64)
   email = models.EmailField()


class Author(models.Model):
   name = models.CharField(max_length=32)
   age = models.IntegerField()
   author_detail = models.OneToOneField(to='AuthorDetail', on_delete=models.CASCADE)


class AuthorDetail(models.Model):
   phone = models.BigIntegerField()
   addr = models.CharField(max_length=64)

2 一對多

# 1 增
# 直接寫id
models.Book.objects.create(title='三國演義', price=123.45, publish_id=1)

# 虛擬欄位對象
publish_obj = models.Publish.objects.filter(pk=2).first()
models.Book.objects.create(title='紅樓夢', price=66.21, publish_id=publish_obj.pk)

# 2 刪
models.User.objects.filter(pk=2).delete()

# 3 改
models.User.objects.filter(pk=1).update(publish_id=3)

3 多對多

# 多對多關係表的增刪改查其實就是第三張關係表的增刪改查
# 1 通過book表給author表添加作者,通過第三張表
book_obj = models.Book.objects.filter(pk=1).first()
book_obj.authors # 相當於進入authorsDetail表
book_obj.authors.add(1)
book_obj.authors.add(2,3)
author_obj = models.Author.objects.filter(pk=2).first()
book_obj.author.add(author_obj.pk)


# 2 刪
remove(2)

# 3 改
括弧內必須傳一個可迭代對象
set([1,2])

# 4 清空
clear()

4 正反向概念

# 正向
看外鍵欄位在哪個表,外鍵欄位所在表查外鍵欄位的表就是正向
book--->外鍵欄位在book表--->publish(正向)

# 反向
反之

"""
正向查詢按欄位
反向查詢按表名小寫
"""

5 多表的跨表查詢

子查詢(基於對象的跨表查詢)
# 1 查詢書籍主鍵為1的出版社名稱
book_obj = models.Book.objects.filter(pk=1).first()
publish_obj = book_obj.publish
publish_obj.name

# 2 查詢書籍主鍵為2的作者
book_obj = models.Book.objects.filter(pk=2).first()
author_obj = book_obj.authors.all() # 結果可能有多個加all

# 3 查詢作者為jason的電話號碼
author_obj = models.Author.objects.filter(name='jason').first()
author_detail_obj = authos_obj.author_detail

# 4 查詢出版社是東方出版社出版的書(反向)
publish_obj = models.Publish.objects.filterr(name='東方出版社').first()
book_obj = publish_obj.book_set.all() # 表名小寫_set一般是對對象

# 5 查詢作者是jason寫過的書(反向)
author_obj = models.Author.objects.filter(name='jason').first()
book_obj = author_obj.book_set.all()

# 6 查詢手機號是110的作者姓名
author_detail_obj = models.AuthorDetil.objects.filter(phone=110).first()
author_obj = author_detail_obj.author_set
連表查詢(基於雙下劃線的跨表查詢)
# 1 查詢jason的手機號和作者姓名
# 正向
phone = models.Author.objects.filter(name='jason').values('author_detail__phone','name')
# 反向
models.AuthorDetail.objects.filter(author__name='jason').values('phone', 'author__name')


# 2 查詢書籍主鍵為1的出版社名稱和書的名字
# 正向
models.Book.objects.filter(pk=1).values('title', 'publish__name')
# 反向
models.Publish.objects.filter(book__id=1).values('name', 'book__title')

# 3 查詢書籍主鍵為1的作者姓名
# 正向
models.Book.objects.filter(pk=1).values('authors__name') # 正向查詢按欄位
# 反向
models.author.objects.filter(book__id=1).values('name')

# 4 查詢書籍主鍵1的作者的手機號
models.Book.objects.filter(pk=1).values('authors__author_detail__phone')

 

3 聚合查詢

aggregate()
# 一般是配合分組一起使用
from app01 import models
from django.db.models import Max, Min, Count, Avg, Sum

models.Book.objects.aggregate(Max('price'), Min('price'), Avg('price'), Count('pk'), Sum('price'))

 

4 分組查詢

  • annotate() 內寫聚合函數

  • 重點: 只要你寫的orm得出的結果是一個queryset對象,那麼你就可以無限的.queryset的方法,比如.values, .filter等等

  • values表示group by的欄位

  • values表示取某幾個欄位

  • filter表示where

  • filter表示having

# 1 統計每一本書的作者個數
models.Book.objects.annotate(author_num=Count('authors')).values('author_num') # models後面.什麼就按什麼分組,author_num是作者個數的別名,一個變數,本來跨表是要authors__id的,但是orm很智慧,可以省略__id
models.Book.objects.annotate(author_num=Count('authors__id')).values('author_num')


# 2 統計每個出版社賣的最便宜的書的價格
models.Publish.objects.annotate(min_book_pirce=Min('book__price')).values('min_book_price')
print(res)

# 3 統計不止一個作者的圖書
models.Book.objects.annotate(author_num=Count('authors__id')).filter(author_num__gt=1)
# <QuerySet [<Book: Book object>, <Book: Book object>, <Book: Book object>]>

models.Book.objects.annotate(author_num=Count('authors__id')).filter(author_num__gt=1).values('title', 'author_num')

# 4 查詢每個作者書的總價格
models.Author.objects.annotate(total_price=Sum('book__price')).values('total_price')

重點: 只要你寫的orm得出的結果是一個queryset對象,那麼你就可以無限的.queryset的方法,比如.values, .filter等等

 

5 F查詢

# 1 查詢賣出數大於庫存數的書籍
"""
F能夠幫助你直接獲取數據表中某個欄位在表中對應的數據
"""
from django.db.models import F
models.Book.objects.filter(maichu__gt=F('kucun'))


# 2 將所有書的價格提升50塊
models.Book.objects.update(price=F('price')+50)

# 3 將所有書的名稱後面加上爆款2個字
"""
在操作字元串的時候F不能直接做到字元串的拼接
"""
from django.db.models.functions import Concat
from django.db.models import Value
models.Book.objects.update(title=Concat(F('title').value('爆款')))

 

6 Q查詢

# 1 查詢賣出數大於100或者價格小於600的書籍
models.Book.objects.filter(maichu__gt=100, price__lt=600)
# <QuerySet []> 因為filter內部多個參數是and的關係

 

7 django中開啟事務

"""
原子性
一致性
隔離性
持久性

回滾 roolback

確認
commit
"""
from django.db import transaction
try:
   with transaction.atomic():
       # with中寫的所有orm都屬於一個事務
except Exception as e:
   print(e)

 

8 ORM中常用欄位和參數

//www.cnblogs.com/Dominic-Ji/p/9203990.html

9 資料庫查詢優化

# 1 only與defer