天天看點

第四章:Django特級篇第四章:Django特級篇

文章目錄

  • 第四章:Django特級篇
      • 聚合查詢
      • 分組查詢
      • F與Q查詢
      • django中如何開啟事務
      • orm中常用字段及參數
      • 資料庫查詢優化
      • 圖書管理的圖書增删改查
      • choices參數(資料庫字段設計常見)
      • MTV與MVC模型
      • 多對多三種建立方式
      • Ajax
      • 小例子
      • 前後端傳輸資料的編碼格式(contentType)
      • ajax發送json格式資料
      • ajax發送檔案;
      • django自帶的序列化元件(drf做鋪墊)
      • ajax結合layer彈窗實作二次确認
      • 批量插入
      • 分頁器

第四章:Django特級篇

聚合查詢

# 聚合查詢      aggregate
    """
    聚合查詢通常情況下都是配合分組一起使用的
    隻要是跟資料庫相關的子產品 
        基本上都在django.db.models裡面
        如果上述沒有那麼應該在django.db裡面
    """
    from app01 import models
    from django.db.models import Max,Min,Sum,Count,Avg
    # 1 所有書的平均價格
    # res = models.Book.objects.aggregate(Avg('price'))
    # print(res)
    # 2.上述方法一次性使用
    res = models.Book.objects.aggregate(Max('price'),Min('price'),Sum('price'),Count('pk'),Avg('price'))
    print(res)
           

分組查詢

# 分組查詢  annotate
    """
    MySQL分組查詢都有哪些特點
        分組之後預設隻能擷取到分組的依據 組内其他字段都無法直接擷取了
            嚴格模式
                ONLY_FULL_GROUP_BY
                
    """
    from django.db.models import Max, Min, Sum, Count, Avg
    # 1.統計每一本書的作者個數
    # res = models.Book.objects.annotate()  # models後面點什麼 就是按什麼分組
    # res = models.Book.objects.annotate(author_num=Count('authors')).values('title','author_num')
    """
    author_num是我們自己定義的字段 用來存儲統計出來的每本書對應的作者個數
    """
    # res1 = models.Book.objects.annotate(author_num=Count('authors__id')).values('title','author_num')
    # print(res,res1)
    """
    代碼沒有補全 不要怕 正常寫
    補全給你是pycharm給你的 到後面在伺服器上直接書寫代碼 什麼補全都沒有 顔色提示也沒有
    
    """

    # 2.統計每個出版社賣的最便宜的書的價格(作業:複習原生SQL語句 寫出來)
    # res = models.Publish.objects.annotate(min_price=Min('book__price')).values('name','min_price')
    # print(res)

    # 3.統計不止一個作者的圖書
        # 1.先按照圖書分組 求每一本書對應的作者個數
        # 2.過濾出不止一個作者的圖書
    # res = models.Book.objects.annotate(author_num=Count('authors')).filter(author_num__gt=1).values('title','author_num')
    # """
    # 隻要你的orm語句得出的結果還是一個queryset對象
    # 那麼它就可以繼續無限制的點queryset對象封裝的方法
    #
    # """
    # print(res)

    # 4.查詢每個作者出的書的總價格
    # res = models.Author.objects.annotate(sum_price=Sum('book__price')).values('name','sum_price')
    # print(res)

    """
    如果我想按照指定的字段分組該如何處理呢?
        models.Book.objects.values('price').annotate()
    後續BBS作業會使用
    
    
    你們的機器上如果出現分組查詢報錯的情況
        你需要修改資料庫嚴格模式
    """
           

F與Q查詢

# F查詢
    # 1.查詢賣出數大于庫存數的書籍
    # F查詢
    """
    能夠幫助你直接擷取到表中某個字段對應的資料
    """
    from django.db.models import F
    # res = models.Book.objects.filter(maichu__gt=F('kucun'))
    # print(res)


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


    # 3.将所有書的名稱後面加上爆款兩個字
    """
    在操作字元類型的資料的時候 F不能夠直接做到字元串的拼接
    """
    from django.db.models.functions import Concat
    from django.db.models import Value
    models.Book.objects.update(title=Concat(F('title'), Value('爆款')))
    # models.Book.objects.update(title=F('title') + '爆款')  # 所有的名稱會全部變成空白
           
# Q查詢
    # 1.查詢賣出數大于100或者價格小于600的書籍
    # res = models.Book.objects.filter(maichu__gt=100,price__lt=600)
    """filter括号内多個參數是and關系"""
    from django.db.models import Q
    # res = models.Book.objects.filter(Q(maichu__gt=100),Q(price__lt=600))  # Q包裹逗号分割 還是and關系
    # res = models.Book.objects.filter(Q(maichu__gt=100)|Q(price__lt=600))  # | or關系
    # res = models.Book.objects.filter(~Q(maichu__gt=100)|Q(price__lt=600))  # ~ not關系
    # print(res)  # <QuerySet []>

    # Q的高階用法  能夠将查詢條件的左邊也變成字元串的形式
    q = Q()
    q.connector = 'or'
    q.children.append(('maichu__gt',100))
    q.children.append(('price__lt',600))
    res = models.Book.objects.filter(q)  # 預設還是and關系
    print(res)
           

django中如何開啟事務

"""
事務
	ACID
		原子性
			不可分割的最小機關
		一緻性
			跟原子性是相輔相成
		隔離性
			事務之間互相不幹擾
		持久性
			事務一旦确認永久生效
	
	事務的復原 
		rollback
	事務的确認
		commit
"""
# 目前你隻需要掌握Django中如何簡單的開啟事務
# 事務
    from django.db import transaction
    try:
        with transaction.atomic():
            # sql1
            # sql2
            ...
            # 在with代碼快内書寫的所有orm操作都是屬于同一個事務
    except Exception as e:
        print(e)
    print('執行其他操作')
           

orm中常用字段及參數

# 更多字段
直接參考部落格:https://www.cnblogs.com/Dominic-Ji/p/9203990.html
    
    
AutoField
	主鍵字段 primary_key=True
  
CharField				varchar
	verbose_name	字段的注釋
  max_length		長度
  
IntegerField			int
BigIntegerField		bigint

DecimalField
	max_digits=8
  decimal_places=2

EmailFiled				varchar(254)

DateField					date
DateTimeField			datetime
	auto_now:每次修改資料的時候都會自動更新目前時間
  auto_now_add:隻在建立資料的時候記錄建立時間後續不會自動修改了
    
BooleanField(Field)				- 布爾值類型
	該字段傳布爾值(False/True) 	資料庫裡面存0/1

TextField(Field)					- 文本類型
	該字段可以用來存大段内容(文章、部落格...)  沒有字數限制
  後面的bbs作業 文章字段用的就是TextField


FileField(Field)					- 字元類型
   upload_to = "/data"
  給該字段傳一個檔案對象,會自動将檔案儲存到/data目錄下然後将檔案路徑儲存到資料庫中
  /data/a.txt
  後面bbs作業也會涉及

# 更多字段
直接參考部落格:https://www.cnblogs.com/Dominic-Ji/p/9203990.html

    
# django除了給你提供了很多字段類型之外 還支援你自定義字段
class MyCharField(models.Field):
    def __init__(self,max_length,*args,**kwargs):
        self.max_length = max_length
        # 調用父類的init方法
        super().__init__(max_length=max_length,*args,**kwargs)  # 一定要是關鍵字的形式傳入

    def db_type(self, connection):
        """
        傳回真正的資料類型及各種限制條件
        :param connection:
        :return:
        """
        return 'char(%s)'%self.max_length

# 自定義字段使用
myfield = MyCharField(max_length=16,null=True)



# 外鍵字段及參數
unique=True
	ForeignKey(unique=True)   ===			OneToOneField()
  # 你在用前面字段建立一對一 orm會有一個提示資訊 orm推薦你使用後者但是前者也能用
  
db_index
	如果db_index=True 則代表着為此字段設定索引
  (複習索引是什麼)

to_field
	設定要關聯的表的字段  預設不寫關聯的就是另外一張的主鍵字段

on_delete
	當删除關聯表中的資料時,目前表與其關聯的行的行為。
  """
  django2.X及以上版本 需要你自己指定外鍵字段的級聯更新級聯删除
  """
           

資料庫查詢優化

only與defer	
select_related與prefetch_related

"""
orm語句的特點:
	惰性查詢
		如果你僅僅隻是書寫了orm語句 在後面根本沒有用到該語句所查詢出來的參數
		那麼orm會自動識别 直接不執行
"""
# only與defer
# res = models.Book.objects.all()
    # print(res)  # 要用資料了才會走資料庫

    # 想要擷取書籍表中所有數的名字
    # res = models.Book.objects.values('title')
    # for d in res:
    #     print(d.get('title'))
    # 你給我實作擷取到的是一個資料對象 然後點title就能夠拿到書名 并且沒有其他字段
    # res = models.Book.objects.only('title')
    # res = models.Book.objects.all()
    # print(res)  # <QuerySet [<Book: 三國演義爆款>, <Book: 紅樓夢爆款>, <Book: 論語爆款>, <Book: 聊齋爆款>, <Book: 老子爆款>]>
    # for i in res:
        # print(i.title)  # 點選only括号内的字段 不會走資料庫
        # print(i.price)  # 點選only括号内沒有的字段 會重新走資料庫查詢而all不需要走了

    res = models.Book.objects.defer('title')  # 對象除了沒有title屬性之外其他的都有
    for i in res:
        print(i.price)
    """
    defer與only剛好相反
        defer括号内放的字段不在查詢出來的對象裡面 查詢該字段需要重新走資料
        而如果查詢的是非括号内的字段 則不需要走資料庫了

    """
    

# select_related與prefetch_related
# select_related與prefetch_related  跟跨表操作有關
    # res = models.Book.objects.all()
    # for i in res:
    #     print(i.publish.name)  # 每循環一次就要走一次資料庫查詢

    # res = models.Book.objects.select_related('publish')  # INNER JOIN
    """
    select_related内部直接先将book與publish連起來 然後一次性将大表裡面的所有資料
    全部封裝給查詢出來的對象
        這個時候對象無論是點選book表的資料還是publish的資料都無需再走資料庫查詢了
    
    select_related括号内隻能放外鍵字段    一對多 一對一
        多對多也不行
    
    """
    # for i in res:
    #     print(i.publish.name)  # 每循環一次就要走一次資料庫查詢

    res = models.Book.objects.prefetch_related('publish')  # 子查詢
    """
    prefetch_related該方法内部其實就是子查詢
        将子查詢查詢出來的所有結果也給你封裝到對象中
        給你的感覺好像也是一次性搞定的
    """
    for i in res:
        print(i.publish.name)
           

圖書管理的圖書增删改查

from django.shortcuts import render,redirect,HttpResponse
from app01 import models
# Create your views here.

def home(request):
    return render(request,'home.html')


def book_list(request):
    # 先查詢出所有的書籍資訊 傳遞給html頁面
    book_queryset = models.Book.objects.all()
    return render(request,'book_list.html',locals())


def book_add(request):
    if request.method == 'POST':
        # 擷取前端送出過來的所有資料
        title = request.POST.get("title")
        price = request.POST.get("price")
        publish_date = request.POST.get("publish_date")
        publish_id = request.POST.get("publish")
        authors_list = request.POST.getlist("authors")  # [1,2,3,4,]
        # 操作資料庫存儲資料
        # 書籍表
        book_obj = models.Book.objects.create(title=title,price=price,publish_date=publish_date,publish_id=publish_id)
        # 書籍與作者的關系表
        book_obj.authors.add(*authors_list)
        # 跳轉到書籍的展示頁面
        """
        redirect括号内可以直接寫url
        其實也可以直接寫别名
        
        但是如果你的别名需要額外給參數的話,那麼就必須使用reverse解析了
        """
        return redirect('book_list')


    # 先擷取目前系統中所有的出版社資訊和作者資訊
    publish_queryset = models.Publish.objects.all()
    author_queryset = models.Author.objects.all()
    return render(request,'book_add.html',locals())


def book_edit(request,edit_id):
    # 擷取目前使用者想要編輯的書籍對象 展示給使用者看
    edit_obj = models.Book.objects.filter(pk=edit_id).first()
    if request.method == 'POST':
        title = request.POST.get("title")
        price = request.POST.get("price")
        publish_date = request.POST.get("publish_date")
        publish_id = request.POST.get("publish")
        authors_list = request.POST.getlist("authors")  # [1,2,3,4,]
        models.Book.objects.filter(pk=edit_id).update(title=title,
                                                      price=price,
                                                      publish_date=publish_date,
                                                      publish_id=publish_id
                                                      )
        # 該第三張關系表
        edit_obj.authors.set(authors_list)
        return redirect('book_list')

    publish_queryset = models.Publish.objects.all()
    author_queryset = models.Author.objects.all()
    return render(request,'book_edit.html',locals())


def book_delete(request,delete_id):
    # 簡單粗暴 直接删除
    models.Book.objects.filter(pk=delete_id).delete()
    # 直接跳轉到展示頁
    return redirect('book_list')
           

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
    
    
    參考部落格位址:https://www.cnblogs.com/Dominic-Ji/p/10580579.html
 
# 實際項目案例
# CRM相關内部表
class School(models.Model):
    """
    校區表
    如:
        北京沙河校區
        上海校區

    """
    title = models.CharField(verbose_name='校區名稱', max_length=32)

    def __str__(self):
        return self.title

class Course(models.Model):
    """
    課程表
    如:
        Linux基礎
        Linux架構師
        Python自動化開發精英班
        Python自動化開發架構師班
        Python基礎班
        go基礎班
    """
    name = models.CharField(verbose_name='課程名稱', max_length=32)

    def __str__(self):
        return self.name

class Department(models.Model):
    """
    部門表
    市場部     1000
    銷售       1001

    """
    title = models.CharField(verbose_name='部門名稱', max_length=16)
    code = models.IntegerField(verbose_name='部門編号', unique=True, null=False)

    def __str__(self):
        return self.title

class UserInfo(models.Model):
    """
    員工表
    """

    name = models.CharField(verbose_name='員工姓名', max_length=16)
    email = models.EmailField(verbose_name='郵箱', max_length=64)
    depart = models.ForeignKey(verbose_name='部門', to="Department",to_field="code")
    user=models.OneToOneField("User",default=1)
    def __str__(self):
        return self.name

class ClassList(models.Model):
    """
    班級表
    如:
        Python全棧  面授班  5期  10000  2017-11-11  2018-5-11
    """
    school = models.ForeignKey(verbose_name='校區', to='School')
    course = models.ForeignKey(verbose_name='課程名稱', to='Course')
    semester = models.IntegerField(verbose_name="班級(期)")


    price = models.IntegerField(verbose_name="學費")
    start_date = models.DateField(verbose_name="開班日期")
    graduate_date = models.DateField(verbose_name="結業日期", null=True, blank=True)
    memo = models.CharField(verbose_name='說明', max_length=256, blank=True, null=True, )

    teachers = models.ManyToManyField(verbose_name='任課老師', to='UserInfo',limit_choices_to={'depart':1002})
    tutor = models.ForeignKey(verbose_name='班主任', to='UserInfo',related_name="class_list",limit_choices_to={'depart':1006})


    def __str__(self):
        return "{0}({1}期)".format(self.course.name, self.semester)


class Customer(models.Model):
    """
    客戶表
    """
    qq = models.CharField(verbose_name='qq', max_length=64, unique=True, help_text='QQ号必須唯一')

    name = models.CharField(verbose_name='學生姓名', max_length=16)
    gender_choices = ((1, '男'), (2, '女'))
    gender = models.SmallIntegerField(verbose_name='性别', choices=gender_choices)

    education_choices = (
        (1, '重點大學'),
        (2, '普通大學'),
        (3, '獨立院校'),
        (4, '民辦大學'),
        (5, '大專'),
        (6, '民辦專科'),
        (7, '高中'),
        (8, '其他')
    )
    education = models.IntegerField(verbose_name='學曆', choices=education_choices, blank=True, null=True, )
    graduation_school = models.CharField(verbose_name='畢業學校', max_length=64, blank=True, null=True)
    major = models.CharField(verbose_name='所學專業', max_length=64, blank=True, null=True)

    experience_choices = [
        (1, '在校生'),
        (2, '應屆畢業'),
        (3, '半年以内'),
        (4, '半年至一年'),
        (5, '一年至三年'),
        (6, '三年至五年'),
        (7, '五年以上'),
    ]
    experience = models.IntegerField(verbose_name='工作經驗', blank=True, null=True, choices=experience_choices)
    work_status_choices = [
        (1, '在職'),
        (2, '無業')
    ]
    work_status = models.IntegerField(verbose_name="職業狀态", choices=work_status_choices, default=1, blank=True,
                                      null=True)
    company = models.CharField(verbose_name="目前就職公司", max_length=64, blank=True, null=True)
    salary = models.CharField(verbose_name="目前薪資", max_length=64, blank=True, null=True)

    source_choices = [
        (1, "qq群"),
        (2, "内部轉介紹"),
        (3, "官方網站"),
        (4, "百度推廣"),
        (5, "360推廣"),
        (6, "搜狗推廣"),
        (7, "騰訊課堂"),
        (8, "廣點通"),
        (9, "高校宣講"),
        (10, "管道代理"),
        (11, "51cto"),
        (12, "智彙推"),
        (13, "網盟"),
        (14, "DSP"),
        (15, "SEO"),
        (16, "其它"),
    ]
    source = models.SmallIntegerField('客戶來源', choices=source_choices, default=1)
    referral_from = models.ForeignKey(
        'self',
        blank=True,
        null=True,
        verbose_name="轉介紹自學員",
        help_text="若此客戶是轉介紹自内部學員,請在此處選擇内部學員姓名",
        related_name="internal_referral"
    )
    course = models.ManyToManyField(verbose_name="咨詢課程", to="Course")

    status_choices = [
        (1, "已報名"),
        (2, "未報名")
    ]
    status = models.IntegerField(
        verbose_name="狀态",
        choices=status_choices,
        default=2,
        help_text=u"選擇客戶此時的狀态"
    )

    consultant = models.ForeignKey(verbose_name="課程顧問", to='UserInfo', related_name='consultanter',limit_choices_to={'depart':1001})

    date = models.DateField(verbose_name="咨詢日期", auto_now_add=True)
    recv_date = models.DateField(verbose_name="目前課程顧問的接單日期", null=True)
    last_consult_date = models.DateField(verbose_name="最後跟進日期", )

    def __str__(self):
        return self.name

class ConsultRecord(models.Model):
    """
    客戶跟進記錄
    """
    customer = models.ForeignKey(verbose_name="所咨詢客戶", to='Customer')
    consultant = models.ForeignKey(verbose_name="跟蹤人", to='UserInfo',limit_choices_to={'depart':1001})
    date = models.DateField(verbose_name="跟進日期", auto_now_add=True)
    note = models.TextField(verbose_name="跟進内容...")

    def __str__(self):
        return self.customer.name + ":" + self.consultant.name

class Student(models.Model):
    """
    學生表(已報名)
    """
    customer = models.OneToOneField(verbose_name='客戶資訊', to='Customer')
    class_list = models.ManyToManyField(verbose_name="已報班級", to='ClassList', blank=True)

    emergency_contract = models.CharField(max_length=32, blank=True, null=True, verbose_name='緊急聯系人')
    company = models.CharField(verbose_name='公司', max_length=128, blank=True, null=True)
    location = models.CharField(max_length=64, verbose_name='所在區域', blank=True, null=True)
    position = models.CharField(verbose_name='崗位', max_length=64, blank=True, null=True)
    salary = models.IntegerField(verbose_name='薪資', blank=True, null=True)
    welfare = models.CharField(verbose_name='福利', max_length=256, blank=True, null=True)
    date = models.DateField(verbose_name='入職時間', help_text='格式yyyy-mm-dd', blank=True, null=True)
    memo = models.CharField(verbose_name='備注', max_length=256, blank=True, null=True)

    def __str__(self):
        return self.customer.name

class ClassStudyRecord(models.Model):
    """
    上課記錄表 (班級記錄)
    """
    class_obj = models.ForeignKey(verbose_name="班級", to="ClassList")
    day_num = models.IntegerField(verbose_name="節次", help_text=u"此處填寫第幾節課或第幾天課程...,必須為數字")
    teacher = models.ForeignKey(verbose_name="講師", to='UserInfo',limit_choices_to={'depart':1002})
    date = models.DateField(verbose_name="上課日期", auto_now_add=True)

    course_title = models.CharField(verbose_name='本節課程标題', max_length=64, blank=True, null=True)
    course_memo = models.TextField(verbose_name='本節課程内容概要', blank=True, null=True)
    has_homework = models.BooleanField(default=True, verbose_name="本節有作業")
    homework_title = models.CharField(verbose_name='本節作業标題', max_length=64, blank=True, null=True)
    homework_memo = models.TextField(verbose_name='作業描述', max_length=500, blank=True, null=True)
    exam = models.TextField(verbose_name='踩分點', max_length=300, blank=True, null=True)

    def __str__(self):
        return "{0} day{1}".format(self.class_obj, self.day_num)

class StudentStudyRecord(models.Model):
    '''
    學生學習記錄
    '''
    classstudyrecord = models.ForeignKey(verbose_name="第幾天課程", to="ClassStudyRecord")
    student = models.ForeignKey(verbose_name="學員", to='Student')







    record_choices = (('checked', "已簽到"),
                      ('vacate', "請假"),
                      ('late', "遲到"),
                      ('noshow', "缺勤"),
                      ('leave_early', "早退"),
                      )
    record = models.CharField("上課紀錄", choices=record_choices, default="checked", max_length=64)
    score_choices = ((100, 'A+'),
                     (90, 'A'),
                     (85, 'B+'),
                     (80, 'B'),
                     (70, 'B-'),
                     (60, 'C+'),
                     (50, 'C'),
                     (40, 'C-'),
                     (0, ' D'),
                     (-1, 'N/A'),
                     (-100, 'COPY'),
                     (-1000, 'FAIL'),
                     )
    score = models.IntegerField("本節成績", choices=score_choices, default=-1)
    homework_note = models.CharField(verbose_name='作業評語', max_length=255, blank=True, null=True)
    note = models.CharField(verbose_name="備注", max_length=255, blank=True, null=True)

    homework = models.FileField(verbose_name='作業檔案', blank=True, null=True, default=None)
    stu_memo = models.TextField(verbose_name='學員備注', blank=True, null=True)
    date = models.DateTimeField(verbose_name='送出作業日期', auto_now_add=True)

    def __str__(self):
        return "{0}-{1}".format(self.classstudyrecord, self.student)
         
"""
chocies參數使用場景是非常廣泛的
"""
           

MTV與MVC模型

# MTV:Django号稱是MTV模型
M:models
T:templates
V:views
# MVC:其實django本質也是MVC
M:models
V:views
C:controller
l:logic
  
# vue架構:MVVM模型
           

多對多三種建立方式

# 全自動:利用orm自動幫我們建立第三張關系表
	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提供操作第三張關系表的方法...
	不足之處:第三張關系表的擴充性極差(沒有辦法額外添加字段...)
	"""
# 純手動
	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')
    c
  '''
  優點:第三張表完全取決于你自己進行額外的擴充
  不足之處:需要寫的代碼較多,不能夠再使用orm提供的簡單的方法
  不建議你用該方式
  '''

# 半自動
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這四個方法
"""

# 總結:你需要掌握的是全自動和半自動 為了擴充性更高 一般我們都會采用半自動(寫代碼要給自己留一條後路)
           

Ajax

"""
異步送出
局部重新整理
例子:github注冊
	動态擷取使用者名實時的跟後端确認并實時展示的前端(局部重新整理)
	
朝後端發送請求的方式
	1.浏覽器位址欄直接輸入url回車						   GET請求
	2.a标簽href屬性											    GET請求
	3.form表單														 GET請求/POST請求
	4.ajax																GET請求/POST請求	
	
AJAX 不是新的程式設計語言,而是一種使用現有标準的新方法(比較裝飾器)


AJAX 最大的優點是在不重新加載整個頁面的情況下,可以與伺服器交換資料并更新部分網頁内容。(這一特點給使用者的感受是在不知不覺中完成請求和響應過程)


Ajax我們隻學習jQuery封裝之後的版本(不學原生的 原生的複雜并且在實際項目中也一般不用)
是以我們在前端頁面使用ajax的時候需要確定導入了jQuery
ps:并不隻有jQuery能夠實作ajax,其他的架構也可以 但是換湯不換藥 原理是一樣的
"""
           

小例子

"""
頁面上有三個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裡面配置一個參數
			(後面再講)
"""
           

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

# 我們主要研究post請求資料的編碼格式
"""
get請求資料就是直接放在url後面的
url?username=jason&password=123
"""

# 可以朝後端發送post請求的方式
	"""
	1.form表單
	2.ajax請求
	"""

  
"""
前後端傳輸資料的編碼格式
	urlencoded
	
	formdata
	
	json
"""
# 研究form表單
	預設的資料編碼格式是urlencoded
  資料格式:username=jason&password=123
  django後端針對符合urlencoded編碼格式的資料都會自動幫你解析封裝到request.POST中
  	username=jason&password=123	>>> request.POST
  
  如果你把編碼格式改成formdata,那麼針對普通的鍵值對還是解析到request.POST中而将檔案解析到request.FILES中
  
  form表單是沒有辦法發送json格式資料的
 

# 研究ajax
	預設的編碼格式也是urlencoded
  資料格式:username=jason&age=20
	django後端針對符合urlencoded編碼格式的資料都會自動幫你解析封裝到request.POST中
  	username=jason&age=20	>>> request.POST
           

ajax發送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擷取并處理
"""
           

ajax發送檔案;

"""
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中
"""
           

django自帶的序列化元件(drf做鋪墊)

"""
如果發現你可以直接使用MySQL但是無法使用sqlite3
不要慌張不要恐懼 你隻需要按照之前MySQL的操作将sqlite3的驅動裝一下即可
"""
# 需求:在前端給我擷取到後端使用者表裡面所有的資料 并且要是清單套字典
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}}
]
寫接口就是利用序列化元件渲染資料然後寫一個接口文檔 該交代交代一下就完事
"""
           

ajax結合layer彈窗實作二次确認

"""
自己要學會如何拷貝
學會基于别人的基礎之上做修改
研究各個參數表示的意思 然後找葫蘆畫瓢
"""
<script>
        $('.del').click(function (){
            //詢問框
            let currentBtn = $(this);
          	var index;
            layer.confirm('你确定要删除嗎?', {
              btn: ['确定','取消'] //按鈕
            }, function(){

                // 發送ajax請求
                $.ajax({
                    url:'/delete_user/?del_id=' + $(this).attr('del_id'),
                    {#url:'/delete_user/' ,#}
                    type:"get",
                    data:{'del_id':currentBtn.attr('del_id')},
                    beforeSend:function () {
                        //加載層
                        index = layer.load(0, {shade: false}); //0代表加載的風格,支援0-2
                    },
                    complete: function(){
                         layer.close(index)
                    },
                    success:function (ret) {
                        if (ret.code == 200) {
                            layer.msg(ret.msg, {icon: 1}, function () {
                                {#window.location.reload()#}
                                currentBtn.parent().parent().remove()
                            });
                        } else  {
                            layer.msg('完了,未知錯誤', {icon: 2});
                        }
                    }
                })
            });
        })
    </script>
           

批量插入

def ab_pl(request):
    # 先給Book插入一萬條資料
    # for i in range(10000):
    #     models.Book.objects.create(title='第%s本書'%i)
    # # 再将所有的資料查詢并展示到前端頁面
    book_queryset = models.Book.objects.all()

    # 批量插入
    # book_list = []
    # for i in range(100000):
    #     book_obj = models.Book(title='第%s本書'%i)
    #     book_list.append(book_obj)
    # models.Book.objects.bulk_create(book_list)
    """
    當你想要批量插入資料的時候 使用orm給你提供的bulk_create能夠大大的減少操作時間
    :param request: 
    :return: 
    """
    return render(request,'ab_pl.html',locals())
           

分頁器

"""
總資料100 每頁展示10 需要10
總資料101 每頁展示10 需要11
總資料99 每頁展示10  需要10

如何通過代碼動态的計算出到底需要多少頁?


在制作頁碼個數的時候 一般情況下都是奇數個		符合中國人對稱美的标準
"""
# 分頁
    book_list = models.Book.objects.all()

    # 想通路哪一頁
    current_page = request.GET.get('page',1)  # 如果擷取不到目前頁碼 就展示第一頁
    # 資料類型轉換
    try:
        current_page = int(current_page)
    except Exception:
        current_page = 1
    # 每頁展示多少條
    per_page_num = 10
    # 起始位置
    start_page = (current_page - 1) * per_page_num
    # 終止位置
    end_page = current_page * per_page_num

    # 計算出到底需要多少頁
    all_count = book_list.count()

    page_count, more = divmod(all_count, per_page_num)
    if more:
        page_count += 1

    page_html = ''
    xxx = current_page
    if current_page < 6:
        current_page = 6
    for i in range(current_page-5,current_page+6):
        if xxx == i:
            page_html += '<li class="active"><a href="?page=%s" target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow" >%s</a></li>'%(i,i)
        else:
            page_html += '<li><a href="?page=%s" target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow" >%s</a></li>'%(i,i)



    book_queryset =  book_list[start_page:end_page]
    
"""
django中有自帶的分頁器子產品 但是書寫起來很麻煩并且功能太簡單
是以我們自己想法和設法的寫自定義分頁器

上述推導代碼你無需掌握 隻需要知道内部邏輯即可

我們基于上述的思路 已經封裝好了我們自己的自定義分頁器 
之後需要使用直接拷貝即可
"""
           

作者:吳常文

出處:https://blog.csdn.net/qq_41405475

本文版權歸作者和CSDN共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接配接。