1. 程式人生 > >Django值聚合,分組,事物,cookie,session

Django值聚合,分組,事物,cookie,session

1,聚合(aggregate):是queryset的一個 終止語句,它返回一個包含鍵值對的字典,鍵是的名稱是聚合值的識別符號,值是計算出來的聚合值,鍵的名稱是按照欄位和聚合函式自動生成出來的.用到的內建函式是看下程式碼↓

from django.db.models import Avg, Max, Min, Count, Sum

聚合程式碼

import os
if __name__ == '__main__':
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day_67.settings")
    import django
    django.setup()
    from app01.models import Student, Classroom, Teacher,Person
    from django.db.models import Max, Min, Sum, Avg, Count
    # data = Student.objects.aggregate(Max("id"))
    # print(data)

    # 1,聚合的單表查詢:
    # 查詢人類女性物件中年齡的平均值?
    # data1 = Person.objects.aggregate(Avg("age"), Max("gender"))
    # print(data1)
    # 因為在性別中只有2個有效資料"1","2",所有查詢app01_teacher的時候自app01_teacher動會把資料庫中不合法的資料過濾掉
    # 1.1,聚合查詢的重新命名(當有多個重新命名按位置引數,關鍵字引數排列)
    # data6 = Person.objects.aggregate(avg=Avg("age"))
    # print(data6)
    # 2.1,外來鍵的查詢
    # 查詢學生關聯表的最大id值
    # data2 = Student.objects.aggregate(Max("classroom__id"))
    # print(data2)
    # 2.2,外來鍵的反向查詢
    # 查詢學生表平均id值(通過班級表的聚合)
    # data3 = Classroom.objects.aggregate(Avg("student__id"))
    # 3.1,多對多聚合正向查詢
    # data4 = Teacher.objects.aggregate(Min("students__name"))
    # print(data4)
    # 3.2,多對多的反向聚合查詢
    # data5 =
    # 查出來的是一個一個數據彙總,返回一個字典

    # 1,分組
    # 1.1,單表的分組查詢
    # obj7 = Person.objects.annotate(Min("age")).values()
    # for el in obj7:
    #     print(el)  # 預設按id值分組
    # 2,外來鍵的分組查詢
    # 2.1,外來鍵的正向查詢
    # obj8 = Student.objects.annotate(Max("classroom")).values()
    # for el in obj8:
    #     print(el)  # 預設以id分組,故每一個id是一個組

    # obj9 = Classroom.objects.annotate(Max("student__id")).values()
    # for el in obj9:
    #     print(el)  # 查詢班級裡邊關聯學生的最大id值

    # 查詢學生表中以班級id分組最大的id值
    # obj10 = Student.objects.values("classroom__id").annotate(Max("id"))
    # for el in obj10:
    #     print(el)

    # 查詢第三張表中教師名字出現的次數
    # obj11 = Teacher.objects.values("students__teacher__name").annotate(Count("name"))
    # for el in obj11:
    #     print(el)

    # 查詢每個教師帶的學生數
    # obj12 = Student.objects.values("teacher__name").annotate(Count("name"))
    # for el in obj12:
    #     print(el)

 小結:在聚合查詢中不指定分組,就預設指定id值分組,指定分組就要用到value("指定分組欄位")

前邊指定了分組,此時再查詢,就會得到一個字典,在不指定分組的情況下的到的是一個queryset物件,需要value取到裡邊的詳細值

2,F()查詢和Q查詢

2.1>Django會幫我們提供F()來做跨欄位之間的比較,F()例項化的物件可以引用欄位,來比較同一個model中不同欄位的值

 

import os
if __name__ == '__main__':
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day_67.settings")
    import django
    django.setup()
    from app01.models import Person, Classroom, Teacher, Student
    from django.db.models import F, Q
    # filter帥選出來的是queryset物件列表
    # obj = Person.objects.filter(age__gt=18).values()
    # print(obj)
    # for el in obj:
    #     print(el)

    # F()例項化的物件能夠獲取到某欄位的所有資料,並能動態的作比較
    # obj1 = Person.objects.filter(id__gt=F("gender")).values()
    # for el in obj1:
    #     print(el)

    # 把帥選到的物件的年兩更新到指定的值,不能批量操作
    # obj2 = Person.objects.filter(id=3).update(age=30)
    # print(obj2)

    # 用F()可以批量操作,條件時表中的欄位或資料具有相同的操作
    # obj3 = Person.objects.all().update(age=F("age")*2)
    # 現獲取到該表的所有物件,再進行指定更新表中的欄位

    # Q查詢是查詢是符合多個條件的查詢
    # 篩選id值大於2且小於4的物件
    # obj4 = Person.objects.filter(id__gt=2,id__lt=4).values()
    # for el in obj4:
    #     print(el)

    # obj5 = Person.objects.filter(Q(id__lte=2) | Q(id__gte=5)).values()
    # for el in obj5:
    #     print(el)
    # 只有queryset物件列表才會有values()方法

    # 查詢教師是"eva_j"或者"sylar"ed所有學生
    # obj6 = Student.objects.filter(Q(teacher__name="eva_j") | Q(teacher__name="sylar")).values()
    # for el in obj6:
    #     print(el)

    # 查詢教師是"eva_j"和"sylar"的學生(多表的Q查詢跨表查詢)
    # obj7 = Student.objects.filter(Q(teacher__id__gt=3) & Q(teacher__name="娜扎")).values()
    # for el in obj7:
    #     print(el)

    # 查詢人類中年級大於18,id值大於5的人(單標的查詢)
    # obj8 = Person.objects.filter(Q(age__gt=18) & Q(id__lt=5)).values()
    # for el in obj8:
    #     print(el)

 小結:F()是F類例項化物件查詢,括號裡放表的欄位,在進行批量改操作,或者某一物件進行操作,F(欄位)能動態的獲取到該欄位列的所有資料,從而進行操作

Q()是Q累例項化物件的查詢,適用於多個條件的範圍查詢有not > & > | 邏輯查詢

3,事務:就是在一些實際事物中事情的發展是一系列的,加入由於某些原因,系統突然癱瘓,之前的一些操作就會陷入極大地不安全和不合理的情況,所以需要把之前的操作還原(好比計算機的後退鍵)引申出事物(也可以舉例銀行賺錢A轉錢給B)

事物的特點:當所有的事情發展的步驟都有效的完成,這件事才算完成,否則重新來.

具體Django程式碼如下↓

 

import os
if __name__ == '__main__':
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day_67.settings")
    import django
    django.setup()
    from app01.models import Person, Classroom, Student, Teacher
    try:
        from django.db import transaction

        with transaction.atomic():
            new1_classroom = Classroom.objects.create(name="阿西吧")
            new2_classroom = Classroom.objects.create(name="阿尼瑪")
            new3_classroom = Classroom.objects.create(name="啊哈西")
            xue = 10
            for i in xue:
                print(i)
            new4_classroom = Classroom.objects.create(name="阿拉斯加")
    except Exception as e:
        print(str(e))

 

 4.cookies:cookies具體是指的一段小資訊,它是伺服器傳送出來儲存在瀏覽器上的一組組鍵值對,下次訪問伺服器時會自動袖帶這些鍵值對,以便伺服器提取有效資訊

4.1>cookies的原理:由伺服器產生內容,瀏覽器收到請求後儲存在本地,當瀏覽器再次訪問時,瀏覽器會自動帶上cookie,這樣伺服器就能通過cookie的內容判斷這個是"誰"了.

檢視cookies,必須先得有cookies(伺服器生成了cookies)

  4.2>獲取cookies的語句

  request.COOKIES.get("key")

  request.get_signed_cookie(key, default=RAISE_ERROR, salt=" ",max_age = None)

  引數說明:

  1>default:預設值

  2>salt:加鹽

  3>max_age:後臺控制過期時間

4.3>設定cookie

設定Cookie
rep = HttpResponse(...)
rep = render(request, ...)

rep.set_cookie(key,value,...)
rep.set_signed_cookie(key,value,salt='加密鹽',...)

引數說明:

key, 鍵
value='', 值
max_age=None, 超時時間
expires=None, 超時時間(IE requires expires, so set it if hasn't been already.)
path='/', Cookie生效的路徑,/ 表示根路徑,特殊的:根路徑的cookie可以被任何url的頁面訪問
domain=None, Cookie生效的域名
secure=False, https傳輸
httponly=False 只能http協議傳輸,無法被JavaScript獲取(不是絕對,底層抓包可以獲取到也可以被覆蓋)

4.4>刪除cookie

def logout(request):
    rep = redirect("/login/")
    rep.delete_cookie("user")  # 刪除使用者瀏覽器上之前設定的usercookie值
    return rep

4.5>cookie程式碼

from django.shortcuts import render, redirect, HttpResponse

# Create your views here.


# 為了在每個函式中都能夠增加cookies要用到裝飾器
def login_request(fn):
    def inner(request, *args, **kwargs):
        # 判斷在跳轉頁面的時候cookies設定的值
        if not request.COOKIES.get("is_login") == "miss":
            # 如果cookies的鍵值對不成立則要先返回登入頁面,登陸成功以後,再返回使用者之前要登入的頁面
            # 先獲取到使用者開始想要登入的頁面路徑
            path = request.path_info
            return redirect("/login/?path={}".format(path))
            # 先跳轉login頁面,再跳轉到原來要登入的頁面
        ret = fn(request, *args, **kwargs)

        return ret

    return inner

def login(request):
    # 使用者第二次進來是提交資料,此時是POST請求
    if request.method == "POST":
        # 獲取使用者輸入的內容
        user = request.POST.get("user")
        pwd = request.POST.get("pwd")
        print(user,pwd,type(pwd))
        # 從資料庫中提取資料
        if user == "雪雪" and pwd == "321":
            # 這是判斷如果已經登入成功再次登入此時就不會再讓他進入登入頁面了
            # 從request中獲取鍵是path的值
            path = request.GET.get("path")
            print(path)
            # 第一次獲取到的是空走下邊的if語句
            if path:
                web_page = redirect(path)
            # 當path對應有了值就會直接跳轉這個頁面
            else:
                # 把跳轉頁面儲存到一個變數中
                web_page = redirect("/home/")
            # 在返回頁面前設定cookies值
            web_page.set_cookie("is_login", "miss", max_age=300)
            # 在返回的頁面中設定cookies,前兩個是字串組成key,value,後邊
            # max_age是這一對鍵值對儲存的時間是秒
            return web_page
    # 使用者第一次進來是一個get請求,返回給使用者一個html登入頁面
    return render(request, "login.html")


@login_request  # 裝飾index函式判斷次時使用者的狀態是登入狀態還是為登入狀態
def index(request):
    return HttpResponse("這是index頁面")


@login_request  # 裝飾home函式,用來在返回這個頁面之前判斷是否在登入狀態
def home(request):
    return render(request, "home.html")


def logout(reqyest):
    # 刪除cookies以後跳轉登入的頁面
    web_page = redirect("/login/")
    # 在返回登入頁面前把request裡邊帶的cookies刪除掉
    web_page.delete_cookie("is_login")  # 指定要珊瑚粗的cookies的鍵

    return web_page

5,session

cookie雖然在一定程度上解決了"保持狀態的需求",但是由於cookie本身最大支援4096位元組,以及cookie本身儲存在客戶端,可能被攔截或竊取,因此就需要一種新的東西,他能支援更多的位元組,並且它儲存在伺服器有較高的安全性,這就是session,HTTP協議是無狀態特徵,所以伺服器就不知道訪問者是誰,namecookie就起到橋接的作用

  我們可以給每個客戶端cookie分配一個唯一的id,這樣使用者在訪問時,通過cookie,伺服器就是知道來的人是"誰",我們根據不同cookie的id值,在伺服器上儲存一端時間的 私密資料

  總而言之:cookie彌補了HTTP無狀態的不足,讓伺服器知道來的人是誰,但是cookie以文字的方式儲存在本地,它自身安全較差:所以我們就通過cookie識別 不同的使用者對應的私密資訊就儲存超過4096位元組(我總結的:把儲存在瀏覽器值的你明文變成暗文,且經過演算法位元組變長了)

5.1>Django中session的相關方法

# 獲取、設定、刪除Session中資料
request.session['k1']
request.session.get('k1',None)
request.session['k1'] = 123
request.session.setdefault('k1',123) # 存在則不設定
del request.session['k1']


# 所有 鍵、值、鍵值對
request.session.keys()
request.session.values()
request.session.items()
request.session.iterkeys()
request.session.itervalues()
request.session.iteritems()

# 會話session的key
request.session.session_key

# 將所有Session失效日期小於當前日期的資料刪除
request.session.clear_expired()

# 檢查會話session的key在資料庫中是否存在
request.session.exists("session_key")

# 刪除當前會話的所有Session資料
request.session.delete()
  
# 刪除當前的會話資料並刪除會話的Cookie。
request.session.flush() 
    這用於確保前面的會話資料不可以再次被使用者的瀏覽器訪問
    例如,django.contrib.auth.logout() 函式中就會呼叫它。

# 設定會話Session和Cookie的超時時間
request.session.set_expiry(value)
    * 如果value是個整數,session會在些秒數後失效。
    * 如果value是個datatime或timedelta,session就會在這個時間後失效。
    * 如果value是0,使用者關閉瀏覽器session就會失效。
    * 如果value是None,session會依賴全域性session失效策略。

5.2>session的相關程式碼

from django.shortcuts import render, redirect, HttpResponse

# Create your views here.


def login_reuqire(fn):
    def inner(request, *args, **kwargs):
        if not request.session.get("is_login") == "1":
            path = request.path_info
            return redirect("/login/?path={}".format(path))
        ret = fn(request,*args, **kwargs)
        return ret
    return inner
def login(request):
    # 第二次進來是提交頁面,提交使用者登入的賬號和密碼
    # 此時是POST請求,判斷是第二次進來的請求的方法
    if request.method == "POST":
        # 獲取到使用者提交過來的資料
        user = request.POST.get("user")
        pwd = request.POST.get("pwd")
        # 從資料庫中讀取資料,判斷使用者輸入的是否正確
        if user == "雪雪" and pwd == "321":
            # 獲取其你去網址的地址
            path = request.GET.get("path")
            # 如果path存在,登入成功後,跳轉到要檢視的頁面
            if path:
                web_page = redirect(path)
             # 如果不存在path,就直接跳轉到登入頁面
            else:
                web_page = redirect("/home/")
            # 返回一個網站的頁面
            # 把要返回的主頁面儲存的一個變數中
            # web_page = redirect("/home/")
            # 設定session值
            request.session["is_login"] = "1"
            # request.session.set_expire(0)  # session的sheng,ing週期
            return web_page
    # 第一次登陸是get請求返回給使用者一個登入的頁面
    return render(request, "login.html")

@login_reuqire
def home(request):
    return render(request, "home.html")

@login_reuqire
def index(request):
    return HttpResponse("這是index頁面")


def logout(request):
    request.flush()
    web_page = redirect("/login/")
    return web_page

 在列印終端列印sql語句

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'console':{
            'level':'DEBUG',
            'class':'logging.StreamHandler',
        },
    },
    'loggers': {
        'django.db.backends': {
            'handlers': ['console'],
            'propagate': True,
            'level':'DEBUG',
        },
    }
}

把這段程式碼複製到settings中即可,重啟一下專案