天天看點

python,django架構

前戲:純手撸web架構

第一次推導

# 不足之處
    1、代碼重複
    2、手動處理http格式的資料 并且隻能拿到url字尾,其他資料擷取繁瑣(資料格式一樣處理代碼其實也大緻一樣 重複寫)
    3、并發問題
    


# 可以将web架構了解成服務端
import socket

"""
b'GET /index HTTP/1.1\r\nHost: 127ec-F...
b'GET /favicon.ico HTTP/1.1\r\nHost: 127...

如何做到字尾不同傳回不同的内容
1、fav的那行不看
2、可以通過列印data得知/index 為我們輸入的字尾


"""

server = socket.socket()  # tcp 三次握手四次回收
server.bind(('127.0.0.1',8080))  # ip協定 以太網協定 arp協定..
server.listen(5)   # 池的概念複習


while True:
    conn, addr = server.accept()
    data = conn.recv(1024)
    # print(data)     # 二進制資料,需要解碼
    data = data.decode('utf-8')      # 字元串
    # 擷取字元串中特定的内容,正則,如果字元串有規律也可以考慮用切割
    conn.send(b'HTTP/1.1 200 OK\r\n\r\n')
    current_path = data.split(' ')[1]   # 拿到清單,而我們字尾在d
    print(current_path)     # 拿到字尾
    if current_path == '/index':
        # conn.send(b'index heiheihie')
        with open(r'myheml.html','rb') as f:
            conn.send(f.read())
    elif current_path == '/login':
        conn.send(b'login')
    else:
        conn.send(b'400')
    conn.close()


           

第二次推導

"""
# 借助 wsgiref
1、幫助封裝了socket代碼
2、幫忙處理了http格式的資料(大字典)

web服務網關接口
1、請求來的時候幫助自動拆分http格式資料,并且封裝成好處理的資料格式
2、響應走的時候将資料打包成符合http格式

"""
from wsgiref.simple_server import make_server


def run(env, response):
    """

    :param env: 請求相關的所有資料
    :param response: 響應相關的所有資料
    :return: 傳回浏覽器的資料
    """
    response('200 OK', [])  # 響應首行 響應頭
    # print(env) # 是一個大字典 wsgiref子產品幫忙處理好http格式的資料
    current_path = env.get('PATH_INFO')
    if current_path == '/index':
        return [b'index']
    elif current_path == '/login':
        return [b'login']
    return [b'404 error']


if __name__ == '__main__':
    server = make_server('127.0.0.1', 8081, run)
    """
    會實時監聽上面的位址和端口,隻要有用戶端
    來了都會交給run函數處理(加括号觸發run函數)
    """
    server.serve_forever() # 啟動服務端


           

第三次推導

# 由于第二次推導添加功能太麻煩,是以經過優化後得到以下内容

from wsgiref.simple_server import make_server

# 将env傳入函數内,函數就拿到更多資料,可以做更多操作


def index(env):
    return 'index'


def login(env):
    return 'login'


def error(env):
    return 'error'


urls = [
    ('/index', index),
    ('/login', login)
]


def run(env, response):
    """

    :param env: 請求相關的所有資料
    :param response: 響應相關的所有資料
    :return: 傳回浏覽器的資料
    """
    response('200 OK', [])  # 響應首行 響應頭
    # print(env) # 是一個大字典 wsgiref子產品幫忙處理好http格式的資料
    current_path = env.get('PATH_INFO')
    # 定義一個變量,存儲比對到函數名,一旦比對到将url對應的函數名指派給func
    func = None
    for url in urls:
        if current_path == url[0]:
            func = url[1]
            break   # 比對到一個之後,立刻結束for循環
    # 判斷func是否有值
    if func:
        res = func(env)
    else:
        res = error(env)
    return [res.encode('utf-8')]


if __name__ == '__main__':
    server = make_server('127.0.0.1', 8081, run)
    """
    會實時監聽上面的位址和端口,隻要有用戶端
    來了都會交給run函數處理(加括号觸發run函數)
    """
    server.serve_forever()  # 啟動服務端

           

第四次推導

# 将第三次推導解耦合為三個檔案,一個檔案夾
# 更具不同的功能拆分成不同的py檔案

"""
wsgiref        寫啟動程式
urls.py        路由于視圖函數對應關系
views.py    視圖函數(後端業務邏輯)
templates檔案夾    專門用來存儲html檔案
# 按照功能不同拆分之後 後續添加功能隻需要在urls.py書寫對應關系,在views.py中寫函數邏輯即可
"""



# 第一個檔案wsgiref
from wsgiref.simple_server import make_server
from url import urls
from vleus import *
# 将env傳入函數内,函數就拿到更多資料,可以做更多操作
def run(env, response):
    """

    :param env: 請求相關的所有資料
    :param response: 響應相關的所有資料
    :return: 傳回浏覽器的資料
    """
    response('200 OK', [])  # 響應首行 響應頭
    # print(env) # 是一個大字典 wsgiref子產品幫忙處理好http格式的資料
    current_path = env.get('PATH_INFO')
    # 定義一個變量,存儲比對到函數名,一旦比對到将url對應的函數名指派給func
    func = None
    for url in urls:
        if current_path == url[0]:
            func = url[1]
            break   # 比對到一個之後,立刻結束for循環
    # 判斷func是否有值
    if func:
        res = func(env)
    else:
        res = error(env)
    return [res.encode('utf-8')]


if __name__ == '__main__':
    server = make_server('127.0.0.1', 8081, run)
    """
    會實時監聽上面的位址和端口,隻要有用戶端
    來了都會交給run函數處理(加括号觸發run函數)
    """
    server.serve_forever()  # 啟動服務端




# 第二個檔案 urls.py
from vleus import *

# url于函數的對應關系
urls = [
    ('/index', index),
    ('/login', login),
    ('/xxx',xxx)
]



# 第三個檔案views.py


def index(env):
    return 'index'


def login(env):
    return 'login'


def error(env):
    return 'error'


def xxx(env):
    with open(r'templates/myhtml.html','r',encoding='utf-8') as f:
        return f.read()



# 第四個目錄templates檔案夾
    myhtml.html           

動靜态網頁

靜态網頁
    頁面上的資料是直接寫死的,萬年不變
動态網頁
    資料是實時擷取的
    1、後端擷取目前時間,展示到目前html頁面上
    2、将一個字典傳遞給html檔案,并且可以在檔案上友善快捷操作字典資料
    3、利用wsgiref子產品封裝web架構,加上jinja2模闆文法 結合前端後端資料庫

        
           

時間案例

# 讓html頁面顯示時間
import datetime
def get_time(env):
    current_time = datetime.datetime.now().strftime('%Y-%m-%d %X')
    # 如何将後端擷取到的資料傳遞給html檔案
    with open('templates/myhtml.html','rt',encoding='utf-8') as f:
        data = f.read()
        # data就是一堆字元串
    data = data.replace('asdasdasda',current_time)
    return data           

jinja2子產品案例

# 将一個字典傳遞給html檔案,并且可以在檔案上友善快捷操作字典資料
# 在後端html檔案起作用

pip3 install jinja2

# 模闆文法
{{ user }}}
{{ user.get('username')}}
{{ user.get('age')}}




from jinja2 import Template
def get_dict(env):
    user_dic = {'username':'jason','age':18}
    with  open(r'templates/myhtml.html','r',encoding='utf-8') as f:
        data = f.read()
    tmp = Template(data)
    res = tmp.render(user = user_dic)
    # 給get_dict,html傳遞了一個值,頁面上通過變量名user能夠拿到user_dict
    return res

           

資料庫案例(融彙貫通)

# 利用wsgiref子產品封裝web架構,加上jinja2模闆文法 結合前端後端資料庫

html檔案

<div class="container">
    <dic class="row">
        <div class="col-md-8 col-md-offset-2">
            <h1 class="text-center">使用者資料</h1>
            <table class="table table-hover table-striped"></table>
                <thead>
                    <tr>
                        <th>ID</th>
                        <th>username</th>
                        <th>password</th>
                        <th>hobby</th>
                    </tr>
                </thead>
                <tbody>
                    {% for user_dic in user_list%}
                        <tr>
                            <td>{{user_dic.id}}</td>
                            <td>{{user_dic.username}}</td>
                            <td>{{user_dic.password}}</td>
                            <td>{{user_dic.hobby}}</td>
                        </tr>
                    {% endfor %}

                </tbody>

        </div>
    </dic>
</div>





vleus檔案

import pymysql
def get_user(env):
    # 去資料庫中擷取資料,傳遞給html頁面,借助于模闆文法,發送給浏覽器
    conn = pymysql.connect(
        host = '127.0.0.1',
        port = 3306,
        user = 'root',
        password = 'admin123',
        db = 'day59',
        charset = 'utf8',
        autocomit = True    # 自動送出
    )
    cursor = conn.cursor(cursor = pymysql.cursors.DictCursor)
    sql = 'select * from user'
    affect_rows = cursor.execute(sql)  # 影響的行數
    data_list = cursor.fatchall()   # 字典套數組的模式
    # 将擷取到的資料傳遞給html檔案
    with open(r'templates/myhtml.html','r',encoding='utf-8') as f:
        data = f.read()
    tmp = Template(data)
    res = tmp.render(user_list = data_list)
    # 給html檔案傳遞一個值,可以通過變量user_list就能拿到data_list


           

python三大主流web架構

django
    特點:大而全 自帶的功能特别多,類似航母
    不足:有時候過于笨重

flask
    特點:小而精 自帶的功能特别少,類似遊騎兵
    第三方的子產品特别多,而且越來越小django
    不足:比較依賴于第三方的開發者
    
tornado
    特點:異步非阻塞  支援高并發
        牛逼到甚至可以開發遊戲伺服器
    不足:暫時不會
    

一個架構大緻分為三部分
A:socket部分
B:路由與視圖函數對應關系
C:模闆文法

django
    A用的是别人的    wsgiref子產品
    B用自己的
    C用自己的(沒有jinja2好用,但是也友善)

flask
    A用的是别人的     werkzeug(内部還是wsgiref子產品)
    B用自己的
    C用别人的(jinja2)
    
tornado
    ABC都是自己寫的

           

django架構

前言

注意事項:
    正常啟動django項目要求
    1、計算機名稱不能有中文
    2、pycharm視窗隻開一個項目
    3、項目裡面所有檔案也是不要出現中文
    4、python解釋器盡量使用3.4到3.6之間的版本
        如果項目報錯,可以點選最後一個報錯資訊
        去源碼中,把逗号删掉
        
django版本問題
    市面上有三個版本
    1.x  2.x   3.x(直接忽略)
    1.x 和 2.x 本身差距也不大,學習主要以1.11為例,會講解2.x差別
            
django安裝
    pip3 install django == 1.11.11
    驗證是否成功
    在終端輸入django-admin看看有沒有反應
    
               

django必會指令

linux建立django項目   (重點)
指令行操作
    1、建立django項目
        可以先切換到對應的盤,然後再建立
        django-admin startproject 項目名
            項目名檔案夾
                manage.py
                mysite檔案夾
                    __init__.py
                    settings.py
                    urls.py
                    wsgi.py
    2、啟動django項目(先切換到mysite檔案夾下)
        """
        一定要先切換到項目目錄下
        """
        python3 manage.py runserver
        htpp://127.0.0.1:8000
        
    3、建立應用
        python manage.py startapp app01
        名字應該見名知意
        
注意事項:

# 指令行和pycharm建立的差別
# pycharm建立
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [BASE_DIR / 'templates'] # 拼接templates路徑

]


# linux建立
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': []

]
    
"""
意味着在用指令行建立django項目的時候還需要去配置檔案中配置路徑
"""

# 建立出來的應用第一步先去配置檔案中注冊
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'app1.apps.App1Config',
]           

主要檔案介紹

-mysite項目檔案夾
    --mysite檔案夾
        ---settings.py            配置檔案
        ---urls.py                路由于視圖函數對應的關系
        ---wsgi.py                wsgiref子產品(不考慮)
    --manage.py                    django的入口檔案
    --db.sqlite3                django自帶的sqlite3資料庫(小型資料庫,功能不多有bug)
    --app01檔案夾
        ---admin.py                django背景管理
        ---apps.py                注冊使用
        ---migrations檔案夾      資料庫遷移記錄
        ---models.py            資料庫相關的 模型類(orm)
        ---tests.py                測試檔案
        ---views.py                視圖函數(視圖層)
    
               

django三闆斧

HttpRespose
    傳回字元串類型的資料
    return HttpResponse('你好啊,我是django妹質')
    
render
    傳回html檔案的
    return render(request,'myfilst.html')
    # 方式一:将user_dict傳給html檔案,html檔案通過data取值
    return render(request,'myfilst.html',{'data':user_dic,'data',123})    
    # 方式二:locals會将所在名稱空間中所有名字傳遞給html頁面
    return render(request,'myfilst.html',locals())
    
    
redirect
    重定向
    return redirect('http://47.96.177.8:82/')
    return redirect('/home/')    # 還可以重定向到自己的目錄
    
===============案例===============

from django.shortcuts import render,HttpResponse,redirect


def index(request):
    """

    :param request: 請求相關的所有資料,比之前的env更加牛逼
    :return:
    """
    # return HttpResponse('你好啊,我是django妹質')
    # return render(request,'myfilst.html')  # 自動去tempaltes檔案夾下查找檔案
    # return redirect('http://47.96.177.8:82/')
    return redirect('/home/')
           

靜态檔案配置

"""
我們将html檔案預設放在templates檔案夾下
我們将網站所使用的靜态檔案夾預設都放在static檔案夾下

靜态檔案
    前端已經寫好了的 能夠直接調用使用的檔案
        網站寫好的js檔案
        網站寫好的css檔案
        網站用到的圖檔檔案
        第三方前端架構
        ...
        拿來直接可以使用
"""


# django不會自動建立static檔案夾,需要手動建立
一般情況下我們在static檔案夾下還會進一步劃分
    -static
        --js
        --css
        --img
        其他第三方檔案
        
        
        
"""
在浏覽器中輸入url能夠看到對應的資源
是應為後端提前開設了該資源的接口
如果通路不到資源,說明後端沒有開設該資源的接口
向html檔案就會應為以上原因使用不了bootstrap
file:///D:/pycharm/pythonProject/djangoProject/djangoProject/bootstrap-3.4.1-dist/css/bootstrap.min.css
"""


# 靜态檔案配置
    """
    STATIC_URL = '/static/' # 類似與通路靜态檔案的令牌
    # 通路頁面的時候導入的bootstrap路徑隻有
    # 令牌對了才能拿着字尾去下面清單中查找

    STATICFILES_DIRS = [
    os.path.join(BASE_DIR,'static'),
    os.path.join(BASE_DIR,'static1')
    ]
    
    
# 靜态檔案動态解析
    {% load static %}
    <link href="{% static 'bootstrap-3.4.1-dist/css/bootstrap.min.css' %}" rel="stylesheet">
    <script src="{% static 'bootstrap-3.4.1-dist/js/bootstrap.min.js' %}"></script>
    這樣一來,無論STATIC_URL如何變都能動态擷取令牌




***************************************
當在寫django項目的時候,可能出現後端代碼修改了,但是前端頁面沒有變化的情況
    1、在同一個端口開了好幾個django項目
        而你一直跑的是第一個django項目
    2、浏覽器緩存問題
        settings
            network    
                disable cache勾上
***************************************



           

request對象方法初識

request.method    # 傳回請求方式,并且是全大寫的字元串形式

request.POST    # 擷取使用者post請求送出的普通資料(不包含檔案)
    request.POST.get()    # 隻擷取清單最後一個元素,str類型
    request.POST.getlist()    # 直接将清單取出
    
request.GET        # 擷取使用者送出的get請求資料(url後面的資料)
    request.GET.get()    # 隻擷取清單最後一個元素
    request.GET.getlist()    # 直接将清單取出


"""
get請求攜帶的資料是有大小限制的,大概4kb左右
post請求則沒有限制

"""


# form表單預設是get請求資料
# 不論是get請求還是post請求都會觸發login函數體代碼
http://127.0.0.1:8000/login/?username=&password=
form表單action參數
    1、不寫 預設朝目前所在的url送出資料
    2、全寫,指名道姓
    3、隻寫字尾/ab_render/



# 在前期我們使用django送出post請求的時候,需要去配置檔案中注釋掉一行代碼
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    # 'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]



def login(request):
    """
    get請求和post請求應該有不同的處理機制
    :param request: 請求相關的資料對象,裡面有很多的建議方法
    :return:
    """
    # print(request.method)   # 傳回請求方式,并且是全大寫的字元串
    # if request.method == 'GET':
    #     print('來了老弟')
    #     return render(request,'login.html')
    # elif request.method == 'POST':
    #     return HttpResponse('收到了,寶貝')
    if request.method == 'POST':
        # 擷取使用者資料
        print(request.POST)  # 擷取使用者送出的post請求數(不包含檔案)
        # < QueryDict: {'username': [''], 'password': ['']} >
        # username = request.POST.get('username')
        # asd = request.POST.getlist('username')
        # print(username, type(username))
        # print(asd, type(asd))
        # # get隻會擷取清單最後一個元素

        return HttpResponse('收到了,寶貝')
    # 擷取url後面攜帶的參數
    print(request.GET)
    print(request.GET.get('username'))
    print(request.GET.getlist('username'))
    
    return render(request, 'login.html')

           

pycharm連接配接資料庫

# 找到pycharm databases選項
# 選擇對應資料庫,下載下傳對應驅動           

django連接配接資料庫(mysql)

# 預設用的是sqkite3
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': BASE_DIR / 'db.sqlite3',
    }
}


# django連接配接mysql
    1、第一步配置檔案中配置
        DATABASES = {
            'default': {
                'ENGINE': 'django.db.backends.mysql',
                'NAME': 'bianji',
                'USER':'root',
                'PASSWORD':'Huawei12#$',
                'HOST':'127.0.0.1',
                'PORT':3306,
                'CHARSET':'utf8'
            }
        }
    2、代碼聲明 init檔案指定
        django預設用的是mysqldb子產品連接配接mysql
        但是該子產品相容性不好,需要手動改為pymysql連接配接
        是以需要告訴django使用pymysql
        # 在項目名下的init或者任意應用下的init檔案中書寫代碼
        import pymysql
        pymysql.install_as_MySQLdb()

           

django ORM

"""
orm不會幫你建立庫,隻能建立表的層面
需要提前建立号庫
"""


ORM. 對象關系映射
作用:能夠讓一個不會sql語句的小白也能夠用python代碼操作資料庫
不足:封裝程度太高,有時候sql語句的效率低 需要自己寫sql語句

類        映射        表
對象                記錄
對象屬性        記錄某個字段對應的值



# 1、先去models.py書寫一個類
    # 這個類裡面需要繼承models.Model
    class User(models.Model):
    # id int primary_key auto_increment
    id = models.AutoField(primary_key=True)
    # username varchar(32)
    username = models.CharField(max_length=32,verbose_name='對字段的解釋')
    """
    CharField必須要指定max_length參數,不寫會報錯
    verbose_name:該參數是所有字段都有的,對字段的解釋
    """

    # password int
    password = models.IntegerField(verbose_name='密碼')


class Author(models.Model):
    # 由于一張表中必須要有一個主鍵字段,并且一般情況下都叫id字段
    # 是以orm當你不自定義主鍵字段的時候,orm會自動建立一個名為id主鍵字段
    # 也就意味着後續我們在建立模型表的時候如果主鍵字段名沒有額外的叫法,那麼主鍵字段可以省略不寫
    # username varchar(32)
    username = models.CharField(max_length=32)
    # password int
    password = models.IntegerField()

****************資料庫遷移指令*******************
# 2、資料庫遷移指令
    python manage.py makemigrations  
    # 将操作記錄記錄到mirgrations内,不會操作資料庫
    python manage.py migrate    
    # 将操作真正的同步到資料庫
    # 隻要修改了models.py中更資料庫相關的代碼,就必須重寫執行上述的兩條指令
    
    # pycharm簡單快捷輸入
        tools
        run manage.py task
            自動提示           

利用ORM實作資料的增删改查操作

字段的增删改

# 字段的添加
    1、當表中已經有資料 可以在終端内直接給出預設值
    2、該字段可以為空
        info = models.CharField(max_length=32,verbose_name='個人簡介',null=True)
    3、直接給字段設定預設值
        hobby = models.CharField(max_length=32,verbose_name='興趣愛好',default='dbj
        
        
        
        
# 字段的修改
    直接修改代碼,然後執行資料庫遷移的兩條指令即可
    

# 字段的删除
    直接注釋對應的字段,然後執行資料庫遷移的兩條指令即可
    執行完畢之後字段對應的資料也沒有了
    
    

"""
在操作models.py的時候一定要細心
    千萬不要注釋一些字段
    執行遷移指令之前,先檢查以下自己寫的代碼
"""
    
                   

資料的增删改

from  app1 import models

# 查
    res = models.User.objects.filter(username=username)
    # select * from user where username='jason';
    # 傳回值可以先看成清單套資料的對象格式
    # 也支援索引取值,切片操作,但是不支援負數索引
    # 他也不推薦使用索引方式取值,推薦使用.first():
    user_obj = models.User.objects.filter(username=username).first()
    # filter括号内可以攜帶多個參數,參數與參數之間是and關系


# 增 
    # 第一種增加,create方法
        res = models.User.objects.create(username=username,password=password)
        傳回的是目前被建立對象本身
        print(res,res.username,res.password)
    # 第二種增加,save方法
        user_obj = models.User(username=username,password=password)
        先生成一個類對象,對象調用類方法
        user_obj.save() # 儲存資料


# 删
    # 批量删除(通過修改條件可以實作删除對應資料)
    models.user.objects.filter(id=delete_id).delete()
    


# 改
        # 修改資料方式1(批量更新)
        # models.user.objects.filter(id=edit_id).update(username=username,password=password)
        """
        将filter查詢出來的所有對象全部更新,批量操作,通過篩選主鍵可以實作某一條資料更新
        隻修改被修改的字段
        """
        # 修改資料方式2(單獨更新)
        edit_obj.username = username
        edit_obj.password = password
        edit_obj.save()

# 編輯資料
    1、先擷取使用者想要編輯的主鍵值
        url?edit_id=1
        url/1/
    2、後端查詢出對應的資料展示到前端
        利用input标簽的value屬性
    3、送出post請求修改資料
        前期送出post請求需要去配置檔案中注釋一行
                   

案例:實作登入,注冊,編輯使用者

urls.py檔案

*****************urls.py檔案*******************
from django.contrib import admin
from django.urls import path
from app02 import views
urlpatterns = [
    path('admin/', admin.site.urls),
    # 登入功能
    path('login/', views.login),
    # 注冊功能
    path('register/', views.register),
    # 展示功能
    path('userlist/', views.user_list),
    # 編輯功能
    path('edit_user/', views.edit_user),
    # 删除使用者
    path('delete_user/', views.delete_user),

]           

views.py檔案

*****************views.py檔案*******************
from django.shortcuts import render, HttpResponse, redirect
from app02 import models

# Create your views here.

# 登入功能
def login(request):
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        from app02 import models
        user_obj = models.user.objects.filter(username=username).first()
        if user_obj:
            if password == user_obj.password:
                return HttpResponse('登入成功')
            else:
                return HttpResponse('密碼錯誤')
        return HttpResponse('賬号錯誤')
    return render(request, 'login.html')


# 注冊功能
def register(request):
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        from app02 import models
        # 方式一
        # res = models.user.objects.create(username=username,password=password)
        # 方式二
        user_obj = models.user(username=username, password=password)
        user_obj.save()
    return render(request, 'register.html')

# 展示功能
def user_list(request):
    from app02 import models
    # 查詢表中的資料,方式一
    # data = models.user.objects.filter()
    # print(data)
    user_queryset = models.user.objects.all()
    print(user_queryset)
    # 将函數内的變量都傳給html檔案
    return render(request,'userlist.html',locals())

# 編輯功能
def edit_user(request):
    # 擷取url問号後面的主鍵值
    edit_id = request.GET.get('user_id')
    # 後端查詢出使用者想要編輯的資料對象,展示到前端頁面給使用者檢視和編輯
    edit_obj = models.user.objects.filter(id=edit_id).first()
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        # 去資料庫中修改對應的資料内容
        # 修改資料方式1(批量更新)
        # models.user.objects.filter(id=edit_id).update(username=username,password=password)
        """
        将filter查詢出來的所有對象全部更新,批量操作,通過篩選主鍵可以實作某一條資料更新
        隻修改被修改的字段
        """
        # 修改資料方式2(單獨更新)
        edit_obj.username = username
        edit_obj.password = password
        edit_obj.save()
        """
        上述方法當字段特别多的時候效率會很低
        從頭到尾将所有字段更新一邊,無論字段是否被修改
        """
        # 編輯完跳轉到資料的展示頁面
        return redirect('/userlist/')

    # 将資料對象展示到頁面上
    return render(request,'edit_user.html',locals())

# 删除功能
"""
和編輯功能類似
"""
def delete_user(request):
    # 擷取使用者想要删除的資料id主鍵值
    delete_id = request.GET.get('user_id')
    # 直接去資料庫中找到對應的資料删除即可
    models.user.objects.filter(id=delete_id).delete()
    """
        批量删除
    """
    # 跳轉到展示頁面
    return redirect('/userlist/')           

models.py檔案

*****************models.py檔案*******************
from django.db import models

# Create your models here.

class user(models.Model):
    username = models.CharField(max_length=32)
    password = models.CharField(max_length=32)
    def __str__(self):
        return '%s'%self.username
        
        
*****************html檔案*******************
*****************edit_user.thml檔案*******************
<!DOCTYPE html>
<html lang="en">
<head>

    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.4.0/jquery.min.js"></script>
    {% load static %}
    <link href="{% static 'bootstrap-3.4.1-dist/css/bootstrap.min.css' %}" rel="stylesheet">
    <script src="{% static 'bootstrap-3.4.1-dist/js/bootstrap.min.js' %}"></script>


</head>

<body>

<h1 class="text-center">編輯頁面</h1>
<div class="container">
    <div class="row">
        <div class="col-md-8 col-md-offset-2">
            <form action="" method="post">
                <p>username:<input type="text" name="username" class="form-control" value="{{ edit_obj.username}}"></p>
                <p>password:<input type="text" name="password" class="form-control" value="{{ edit_obj.password }}"></p>
                <input type="submit" class="btn-block btn btn-info" value="編輯">
            </form>

        </div>
    </div>

</div>

</body>
</html>           

login.html檔案

*****************login.html檔案*******************
<!DOCTYPE html>
<html lang="en">
<head>

    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.4.0/jquery.min.js"></script>
    {% load static %}
    <link href="{% static 'bootstrap-3.4.1-dist/css/bootstrap.min.css' %}" rel="stylesheet">
    <script src="{% static 'bootstrap-3.4.1-dist/js/bootstrap.min.js' %}"></script>

</head>

<body>
<h1 class="text-center">登入</h1>
<div class="container">
    <div class="row">
        <div class="col-md-8 col-md-offset-2">
            <form action="" method="post">
                <p>username:<input type="text" name="username" class="form-control"></p>
                <p>password:<input type="text" name="password" class="form-control"></p>
                <input type="submit" class="btn-block btn btn-danger">
            </form>

        </div>
    </div>

</div>

</body>
</html>           

register.html

*****************register.html檔案*******************
<!DOCTYPE html>
<html lang="en">
<head>

    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.4.0/jquery.min.js"></script>
    {% load static %}
    <link href="{% static 'bootstrap-3.4.1-dist/css/bootstrap.min.css' %}" rel="stylesheet">
    <script src="{% static 'bootstrap-3.4.1-dist/js/bootstrap.min.js' %}"></script>

</head>

<body>


<h1 class="text-center">注冊</h1>
<div class="container">
    <div class="row">
        <div class="col-md-8 col-md-offset-2">
            <form action="" method="post">
                <p>username:<input type="text" name="username" class="form-control"></p>
                <p>password:<input type="text" name="password" class="form-control"></p>
                <input type="submit" class="btn-block btn btn-danger">
            </form>

        </div>
    </div>

</div>


</body>
</html>

           

userlist.html檔案

*****************userlist.html檔案*******************
<!DOCTYPE html>
<html lang="en">
<head>

    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.4.0/jquery.min.js"></script>
    {% load static %}
    <link href="{% static 'bootstrap-3.4.1-dist/css/bootstrap.min.css' %}" rel="stylesheet">
    <script src="{% static 'bootstrap-3.4.1-dist/js/bootstrap.min.js' %}"></script>


</head>

<body>

<h1 class="text-center">頁面展示</h1>
<div class="container">
    <div class="row">
        <div class="col-md-8 col-md-offset-2">
            <table class="table table-striped table-hover">
                <thead>
                    <tr>
                        <th>ID</th>
                        <th>username</th>
                        <th>password</th>

                    </tr>
                </thead>
                <tbody>
                    {% for user_obj in user_queryset %}
                    <tr>
                        <td>{{ user_obj.id }}</td>
                        <td>{{ user_obj.username }}</td>
                        <td>{{ user_obj.password }}</td>
                        <td>
                            <a href="/edit_user/?user_id={{ user_obj.id }}" class="btn btn-primary btn-xs">編輯</a>
                            <a href="/delete_user/?user_id={{ user_obj.id }}" class="btn btn-danger btn-xs">删除</a>
                        </td>
                    </tr>

                    {% endfor %}
                    

                </tbody>
            </table>
        </div>
    </div>
</div>


</body>
</html>           

orm如何建立表關系

表與表主鍵的關系
    一對一        外鍵創在任意一方即可
    一對多        外鍵創在多的一方
    多對多        額外創一個表,另外兩張表外鍵指向創的表


"""
orm中如何定義三種關系
# 一對多
publish_wj = models.ForeignKey('Publish',on_delete=models.CASCADE)
# 多對多
authors_wj = models.ManyToManyField('Author')
# 一對一
author_detall = models.OneToOneField('Author', on_delete=models.CASCADE)

ps:on_delete=models.CASCADE級聯操作,但是多對多貌似不用加這個參數

"""

    
"""    
圖書表        圖書表和出版社多對一,和作者表多對多
出版社
作者表        作者表和作者詳情表一對一
作者詳情表
"""    
    
*********************案例代碼*************************
# 圖書表
class Book(models.Model):
    title = models.CharField(max_length=32,verbose_name='頭')
    price = models.DecimalField(max_digits=8, decimal_places=2)
    # 總共八位,小數點後面占兩位
    """
    圖書和出版社是一對多,并且書是多的一方,是以外鍵字段放在書表裡面
    """
    publish_wj = models.ForeignKey('Publish',on_delete=models.CASCADE)
    # to_field參數可以不寫,預設就是與出版社表的主鍵字段做外鍵關聯
    """
    圖書和作者是多對多的關系,ORM外鍵字段建在任意一方均可
    """
    authors_wj = models.ManyToManyField('Author')
    # author是一個虛拟字段,主要是告訴orm,書籍表和作者表是多對多
    # 讓orm自動建立第三張關系表
    # 這裡貌似不用加on_delete=models.CASCADE 級聯删除

# 出版社
class Publish(models.Model):
    name = models.CharField(max_length=32)
    # 位址
    addr = models.CharField(max_length=32)


# 作者表
class Author(models.Model):
    name = models.CharField(max_length=32)
    age = models.IntegerField()
    """
    作者與作者詳情是一對一的府岸西,外鍵在任意一方都行
    """
    author_detall = models.OneToOneField('Author', on_delete=models.CASCADE)


# 作者詳情表
class AuthorDetail(models.Model):
    phone = models.BigIntegerField()    # 或者直接字元類型
    addr = models.CharField(max_length=32)
    
           

django生命周期流程圖

django路由層

urls.py

# 路由比對
url(r'test',views.text),
url(r'testadd',views.testadd)

"""
url方法第一個參數就是正規表達式
    隻要第一個參數正規表達式能夠比對到内容,那麼就會停止往下比對
    直接指向目前比對到的對應視圖函數

在浏覽器輸入url的時候會預設加斜杠
    django内部做重定向
        第一次比對不行
        會自動比對第二次,這一次會加斜杠再來一次

# 取消自動加斜杠
APPEND_SLASH = False/True    # 預設是自動加斜杠的


urlpatterns = [
    path(r'^admin/', admin.site.urls),
    # 首頁
    path(r'^$', views.login),
    # 路由比對
    path(r'^test/$', views.register),
    path(r'^userlist/$', views.user_list),
    # 尾頁404
    path(r'', views.delete_user),

]

如果是test則輸入testasdasd也能比對到
如果是test/則輸入asdasdtest/也能比對到
如果是^test/則輸入test/asdad也可以比對到
如果是^test/$這樣才能精确比對
如果正則裡啥都不寫r'',則表示全部比對這種一般丢到最下面
正則裡是r'^$',這種一般表示首頁,直接記不要問為啥

ps:
    
    ^    比對字元串的開頭
    $    比對字元串的末尾。           

無名分組,有名分組

# 1、無名分組
    """
    分組:就是将某一個正則加小括号括起來
    """
    path(r'^test/(\d+)/', views.register)

    def register(request,xx)
        print(xx)
        pass


    # 無名分組就是将括号内正規表達式比對到的内容當作位置參數傳遞給視圖函數

    ps:
    \d    比對任意數字,等價于 [0-9]



# 2、有名分組

    """
    可以給正規表達式起一個别名
    """
    path(r'^test/(?p<year>\d+)/(?p<year>\d+)', views.register)

    def register(request,year)
        print(year)
        pass

    # 有名分組就是将括号内正規表達式比對到的内容當作關鍵字參數傳遞給視圖函數


# 3、有名無名不能混用,但是同一個分組可以使用n次

# 4、單個分組可以重複使用

    path(r'^test/(\d+)/(\d+)/', views.register)
    def register(request,*args,**kwargs)
        print(args)
        print(kwargs)

    path(r'^test/(?p<year>\d+)/(?p<age>\d+)/', views.register)
    def register(request,*args,**kwargs)
        print(args)
        print(kwargs)           

反向解析

# 通過一些方法得到一個結果,改結果可以直接通路對應的url觸發視圖函數

# 1、反向解析
    # 第一步,先給路由與視圖函數起一個别名
    path(r'^test/', views.register,name='ooo')

    # 第二步反向解析
        後端方向解析:可以拿到資料的主鍵值
            from django.shortcuts import  reverse
            print(reverse('ooo'))
            這樣後端可以拿到解析的url  /test/user_obj.id

        前端反向解析:
             <a href="{% url 'ooo' user_obj.id %}">編輯</a>
             # 該标簽通路的是 /ooo/user_obj.id
            
# 2、無名分組反向解析
    url(r'^index/(\d+)/',views.index,name='xxx')
        # 前端
            {% url 'xxx' 123 %}
        # 後端
            reverse('xxx',args=(1,))
            
# 3、有名分組反向解析
    url(r'^index/(?p<year>\d+)/',views.index,name='ooo')
        # 前端
        <a href="{% url 'ooo' year=123 %}">111</a> 了解
        <a href="{% url 'ooo' 123 %}">222</a>
        # 後端
        reverse('ooo',kwargs=('year',123))    了解
        reverse('ooo',args=(1,))
        
        
# 4、案例
    """
    這個參數寫代碼的時候應該放什麼?
        數字一般放的是資料的主鍵值 資料的編輯和删除url(r'^index/(\d+)/',views.index,name='xxx')

    def edit(request,edit_id):
        pass

    {%for user_obj in user_queryset%}
    <a href="{% url 'xxx' user_obj.id %}">編輯</a>
    {%endfor%}

    案例:通過無名有名,反向解析,完成資料的增删改
    """

           

無名反向解析案例

"""
通過無名反向解析,完成資料的編輯
"""


urls:
from django.contrib import admin
from django.urls import re_path
from app01 import views

urlpatterns = [
    re_path('admin/', admin.site.urls),
    re_path(r'^bianji/', views.bj_user),
    re_path(r'del_user/(\d+)/', views.del_user, name='ooo'),
    re_path(r'edit_user/(\d+)/', views.edit_user, name='eee'),
]

========================================

views:
from django.shortcuts import render, HttpResponse, redirect
import app01.models
from app01 import models
from django.shortcuts import reverse

# Create your views here.


# 編輯頁面
def bj_user(request, ):
    user_queryset = models.User.objects.all()
    # print(reverse('xxx', args=(1,)))
    return render(request, 'bj_user.html', locals())

# 編輯資料
def edit_user(request, edit_id):
    edit_obj = models.User.objects.filter(id=edit_id).filter()
    print(edit_obj)
    if request.method == 'POST':
        name = request.POST.get('username')
        describe = request.POST.get('password')
        models.User.objects.filter(id=edit_id).update(name=name, describe=describe)
        return redirect('/bianji/')
    return render(request, 'edit_user.html', locals())

# 删除資料
def del_user(request, edit_id):
    models.User.objects.filter(id=edit_id).delete()
    return redirect('/bianji/')


=============================================
edit_user.html
<!DOCTYPE html>
<html lang="en">
<head>

    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.4.0/jquery.min.js"></script>
    <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>

</head>

<body>
<h1 class="text-center">編輯頁面</h1>
<div class="container">
    <div class="row">
        <div class="col-md-8 col-md-offset-2">
            <form action="" method="post">
                {% for foo in edit_obj %}
                    <p>username:<input type="text" name="username" class="form-control" value="{{ foo.name }}"></p>
                    <p>password:<input type="text" name="password" class="form-control" value="{{ foo.describe }}"></p>
                    <input type="submit" class="btn-block btn btn-danger">
                {% endfor %}


            </form>

        </div>
    </div>

</div>
</body>
</html>


==============================================
bj_user.html
<!DOCTYPE html>
<html lang="en">
<head>

    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.4.0/jquery.min.js"></script>
    {% load static %}
    <link href="{% static 'bootstrap-3.4.1-dist/css/bootstrap.min.css' %}" rel="stylesheet">
    <script src="{% static 'bootstrap-3.4.1-dist/js/bootstrap.min.js' %}"></script>

</head>

<body>

<h1 class="text-center">展示頁面</h1>
<div class="container">
    <div class="row">
        <div class="col-md-8 col-md-offset-2">
            <table class="table table-striped table-hover">
                <thead>
                    <tr>
                        <th>ID</th>
                        <th>username</th>
                        <th>describe</th>
                    </tr>
                </thead>
                <tbody>
                    {% for user_obj in user_queryset %}
                    <tr>
                        <td>{{ user_obj.id }}</td>
                        <td>{{ user_obj.name }}</td>
                        <td>{{ user_obj.describe }}</td>
                        <td>
{#                            <a href="/edit_user/?user_id={{ user_obj.id }}" class="btn btn-primary btn-xs">編輯</a>#}
                            <a href="{% url 'eee' user_obj.id %}" class="btn btn-primary btn-xs">編輯</a>
                            <a href="{% url 'ooo' user_obj.id %}" class="btn btn-danger btn-xs">删除</a>
                        </td>
                    </tr>

                    {% endfor %}

                </tbody>
            </table>

        </div>
    </div>

</div>


</body>
</html>           

路由分發

"""
每一個應用都可以有自己的templates檔案夾,urls.py  static檔案夾
正是基于上述的特點,django能夠做到分組開發(每個人隻寫自己的app)
二作為組長,隻需要将手下書寫的app全部cp到一個新的django項目中 然後配置檔案裡注冊所有的app,在利用路由分發的特點将所有的app整合起來

當一個django項目中url特别多的時候,總路由urls.py代碼非常備援不好維護
這個時候也可以利用路由分發來減輕總路由的壓力

利用路由分發之後,總路由不在幹路由與視圖的直接對應關系
而是做一個分發處理
    識别目前url屬于那個app的,然後進行轉發
"""


# 1、總路由
from app01 import urls as app01_urls
from app02 import urls as app02_urls
urlpatterns = {
    url(r'^admin/',admin.site.urls),
    # 路由分發
    # 方法一:
    url(r'^app01/',include(app01_urls)),    # 隻要url字首是app01開頭的全部交給app01處理
    url(r'^app02/',include(app02_urls)),
    # 方法二(常用):
    url(r'^app01/',include(app01.urls)),
    url(r'^app02/',include(app02.urls)),
    
}



# 2、子路由
    # app01 urls.py
    from django.conf.urls import url
    from app01 import views
    urlpatterns = {
        url(r'^reg/',views.reg)
    }
    
    
    # app02 urls.py
    from django.conf.urls import url
    from app02 import views
    urlpatterns = {
        url(r'^reg/',views.reg)
    }

           

命名空間(了解)

當我們多人開發app的時候,大家設定的别名一樣時,反向解析則不能自動識别
這個時候可以用過命名空間來區分

# 名稱空間
    # 總路由
    url(r'^app01/',include('app01_urls',namespace='app01')),
    url(r'^app02/',include('app02_urls',namespace='app02'))
    # 解析的時候
    # app01
    urlpatterns = {
        url(r'^reg/',views.reg,name='reg')
    }
    # app02
    urlpatterns = {
        url(r'^reg/',views.reg,name='reg')
    }
    
    # 後端解析
    reverse('app01:reg')
    reverse('app02:reg')
    # 前端解析
    {% url 'app01:reg'%}
    {% url 'app02:reg'%}           

僞靜态(了解)

"""
靜态網頁
    資料是寫死的,萬年不變
    
僞靜态
    将一個動态網頁僞裝成靜态網頁
    
"""
# 實作,直接加個.html
    urlpatterns = {
        url(r'^reg.html/',views.reg,name='reg')
    }
           

django版本差別(了解)

"""
1、django1.x路由層使用的是url方法
    而在2或者3本本中路由層使用的是path方法
    url()第一個參數支援正則
    path()第一個參數不支援正則,寫什麼就比對什麼
    
    
2、雖然path不支援正則,但是它的内部支援五種轉換器
    str,比對除了路徑分隔符(/)之外的非空字元串,這是預設的形式
    int,比對正整數,包含0。
    slug,比對字母、數字以及橫杠、下劃線組成的字元串。
    uuid,比對格式化的uuid,如 075194d3-6885-417e-a8a8-6c931e272f00。
    path,比對任何非空字元串,包含了路徑分隔符(/)(不能用?)
    
    
3、例子
    path('articles/<int:year>/<int:month>/<slug:other>/', views.article_detail) 
    # 針對路徑http://127.0.0.1:8000/articles/2009/123/hello/,path會比對出參數year=2009,month=123,other='hello'傳遞給函數article_detai
"""


           

django視圖層

三闆斧

HttpRespose
    傳回字元串類型的資料
    return HttpResponse('你好啊,我是django妹質')
    
render
    傳回html檔案的
    return render(request,'myfilst.html')
    # 方式一:将user_dict傳給html檔案,html檔案通過data取值
    return render(request,'myfilst.html',{'data':user_dic,'data',123})    
    # 方式二:locals會将所在名稱空間中所有名字傳遞給html頁面
    return render(request,'myfilst.html',locals())
    
    
redirect
    重定向
    return redirect('http://47.96.177.8:82/')
    return redirect('/home/')    # 還可以重定向到自己的目錄
    
===============案例===============

from django.shortcuts import render,HttpResponse,redirect


def index(request):
    """

    :param request: 請求相關的所有資料,比之前的env更加牛逼
    :return:
    """
    # return HttpResponse('你好啊,我是django妹質')
    # return render(request,'myfilst.html')  # 自動去tempaltes檔案夾下查找檔案
    # return redirect('http://47.96.177.8:82/')
    return redirect('/home/')

           

jsonResponse

"""
json格式的資料有什麼用?
    前後端互動需要使用json作為過渡,實作跨語言傳輸資料
"""
import json
from django.http import JsonResponse
def ab_json(request):
    user_dict = {'username':'khw阿斯頓'}
    1 = [1,2,3]
    # 先轉成json格式字元串
    json_str = json.dumps(user_dict,ensure_ascii=False) # 表示不動冒号裡的資料,也就是不将起轉化為ASCII碼
    # 将該字元串傳回
    # return HttpResponse(json_str)
    # return JsonResponse(l,safe=False)
    # 預設隻能序列化字典,序列化其他需要加safe參數           

form表單上傳檔案

"""
form表單上傳檔案夾類型的資料
    1、method必須指定成posts
    2、enctype必須換成formdata
"""


def ab_file(request):
    if request.method == "POST":
        # print(request.POST) 隻能擷取普通的鍵值對資料,檔案不行
        print(request.FILES)    # 擷取檔案資料
        file_obj = request.FILES.get('file') # 檔案對象
        print(file_obj.name)
        with open('file','wb') as f:
            for line in file_obj.chunks(): # 推薦加上chunks方法,其實不加也是一行一行讀取資料
            f.write(line)
    return render(requet,'form.html')


# request對象方法
request.method    # 傳回請求方式,并且是全大寫的字元串形式
request.POST    # 擷取使用者post請求送出的普通資料(不包含檔案)
request.GET        
request.FILES    # 擷取檔案
request.body    # 原生浏覽器發送過來的二進制資料
request.path    # 能擷取url參數
request.get_full_path()        # 能擷取完整的url及問号後面的參數           

FBV與CBV

# 視圖函數既可以是函數也可以是類

# FBV函數
    def index(request):
        return     HttpResponse('index')

# CBV類
# 能夠更具請求方式不同自動比對方法的執行
from django.views import View
    # CBV路由
    url(r'^login/',views.Mylogin.as_view())
    


""" 隻要是處理業務邏輯的視圖函數,形參裡面肯定要有request """
    class Mylogin(view):
        def get(self,request):
            return render(request,'form.html')
            
        def post(self,request):
            return     HttpResponse('post方法')
            
                               

CBV源碼剖析

  • 第一步解析
re_path(r'^login/', views.MyLogin.as_view())
# 上述代碼在啟動django的時候會立即執行as_view方法
# 通過源碼得知該行等價于 re_path(r'^login/', views.view)
# CBV與FBV在路由比對上本質是一樣的,都是路由對應函數的記憶體位址

"""
函數名/方法名 加括号執行優先級最高
猜測
    as_view
        要麼是被@staicmethod修飾的靜态方法
        要麼是被@classmethod修飾的類方法  正确
        
"""
           
  • 第二步解析:解析as_view方法
def as_view(cls, **initkwargs):
        """
        cls 就是我們自己寫的類 MyLogin
        
        """
        def view(request, *args, **kwargs):
            self = cls(**initkwargs)        # cls我們自己寫的類
            # self = Mylogin(**initkwargs)    # 産生一個自己寫的類的對象
            return self.dispatch(request, *args, **kwargs)
            """
              ps:一定要知道self.dispatch這個對象屬性的查找順序
              先從對象自己找
              再去産生對象的類裡面找
              之後再去父類裡找
              總結:看源碼隻要看到self點了一個東西,一定要問自己目前這個self到底是誰
             """
        return view           
  • 第三步解析:解析dispatch源碼
# CBV精髓

def dispatch(self, request, *args, **kwargs):
        # 擷取目前請求的小寫格式,然後對比目前請求方式是否合法
        # get請求為例
        # post請求
        if request.method.lower() in self.http_method_names:
            handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
        """
        反射:通過字元串來操作對象屬性或方法
        handler = getattr(自己寫的類産生的對象, 'get', 當找不到get屬性或者方法會用到這個參數)
        handler = 我們自己寫的類裡面的get方法
        """
        else:
            handler = self.http_method_not_allowed
        return handler(request, *args, **kwargs)
        """
        自動調用get方法
        """           

settings源碼剖析

django模闆層

模闆文法傳值

{{}}:變量相關
{%%}:邏輯相關

def index(request):
    # 模闆文法傳遞的後端python資料類型
    n = 123
    f = 11.11
    s = '字元串'
    b = True
    l = ['地', '瓜']
    t = (111, 222, 333)
    d = {'username': 'dig', 'age': 18, 'info': '這個人有點意思','hobby':[111,222,{'info':'NB'}]}
    se = {'撒旦', '地方', '速度'}

    def func():
        print('我被執行了')
        return '我在等你'

    class MyLogin(object):
        def get_self(self):
            return 'self'

        @staticmethod
        def get_func():
            return 'func'

        @classmethod
        def get_class(cls):
            return 'cls'

        # 對象被展示到html頁面上就類似于執行了列印操作,也會觸發__str__方法
        def __str__(self):
            return '會不會玩'

    obj = MyLogin()
    return render(request, 'index.html', locals())




# 模闆傳值
<p>{{ n }}</p>
<p>{{ f }}</p>
<p>{{ s }}</p>
<p>{{ b }}</p>
<p>{{ l }}</p>
<p>{{ d }}</p>
<p>{{ t }}</p>
<p>{{ se }}</p>
<p>傳遞函數名會自動加括号調用,但是模闆文法不支援給函數傳額外的參數:{{ func }}</p>
<p>傳類名的時候也可以自動加括号調用(執行個體化){{ MyLogin }}</p>
<p>内部能夠自動判斷出目前的變量名是否可以加括号調用,如果可以就會自動執行,這個針對的是函數和類名</p>
<p>{{ obj }}</p>
<p>{{ obj.get_class }}</p>
<p>{{ obj.get_func }}</p>
<p>{{ obj.get_self }}</p>


# 模闆取值
<p>{{ d.username }}</p>
<p>{{ l.0 }}</p>
<p>{{ d.hobby.2.info }}</p>
# 通過點來取值


           

模闆文法之過濾器(最多兩個參數)

def index(request):
    # 模闆文法傳遞的後端python資料類型
    n = 123
    f = 11.11
    s = '字元串'
    b = True
    l = ['地', '瓜','3','4']
    t = (111, 222, 333)
    d = {'username': 'dig', 'age': 18, 'info': '這個人有點意思','hobby':[111,222,{'info':'NB'}]}
    se = {'撒旦', '地方', '速度'}

    def func():
        print('我被執行了')
        return '我在等你'

    class MyLogin(object):
        def get_self(self):
            return 'self'

        @staticmethod
        def get_func():
            return 'func'

        @classmethod
        def get_class(cls):
            return 'cls'

        # 對象被展示到html頁面上就類似于執行了列印操作,也會觸發__str__方法
        def __str__(self):
            return '會不會玩'

    obj = MyLogin()

    file_size = 10240000

    import datetime
    current_time = datetime.datetime.now()

    info = '# 商業轉載請聯系作者獲得授權,非商業轉載請注明出處。'
    egl = 'my name is khw age 18'
    msg = 'i love you and you?'
    hhh = '<h1>地瓜<h1>'
    from django.utils.safestring import mark_safe
    res = mark_safe('<h1>木可<h1>')
    return render(request, 'index.html', locals())





<p>預設長度:{{ s|length }}</p>
<p>預設值(第一個參數布爾值是true就展示第一個參數的值,否則展示預設值):{{ b|default:"啥也不是" }}</p>
<p>檔案大小:{{ file_size|filesizeformat }}</p>
<p>日期格式化:{{ current_time|date:'Y-m-d H:i:s' }}</p>
<p>切片操作(0到4步長為2):{{ l|slice:'0:4:2' }}</p>
<p>切取字元(摘要,後面數字表示截取多少個字元,包含三個點):{{ info|truncatechars:9 }}</p>
<p>切取單詞(按照空格切,中文也是一樣):{{ egl|truncatewords:4 }}</p>
<p>移除特定的字元(該例将空格切除):{{ msg|cut:' ' }}</p>
<p>拼接操作:{{ l|join:"$" }}</p>
<p>拼接操作(加法):{{ n|add:10 }}</p>
<p>拼接操作(還能拼接字元串):{{ s|add:msg }}</p>
<p>轉義:{{ hhh|safe }}</p>



# 轉義
# 前端操作
<p>轉義:{{ hhh|safe }}</p>
# 後端操作
from django.utils.safestring import mark_safe
res = mark_safe('<h1>木可<h1>')
return render(request, 'index.html', locals())
           

模闆文法之标簽

# for循環

    {% for foo in l %}
        <p>{{ forloop }}</p>
        <p>{{ foo }}</p>
        {% empty %}
        <p>for循環可疊代對象是空,根本沒法循環</p>
    {% endfor %}

    {'parentloop': {}, 'counter0': 2, 'counter': 3, 'revcounter': 2, 'revcounter0': 1, 'first': False, 'last': False}
    {'parentloop': {}, 'counter0': 3, 'counter': 4, 'revcounter': 1, 'revcounter0': 0, 'first': False, 'last': True}

    first:表示該for循環是否為第一次
    last:表示該for循環是否為最後一次
    counter0:表示計數 2 表示從2開始
    counter:表示數數,3表示從3開始



# if判斷
    {% if b %}
        <p>貝比</p>
    {% elif s%}
        <p>都來把</p>
    {% else %}
        <p>老貝比</p>
    {% endif %}


# for與if混合使用
    {% for foo in l %}
        {% if forloop.first %}
            <p>這是我的第一次</p>
        {% elif forloop.last %}
            <p>這是最後一次</p>
        {% else %}
            <p>老貝比</p>
        {% endif %}
        {% empty %}
        <p>for循環可疊代對象是空,根本沒法循環</p>
    {% endfor %}


# 處理字典的其他方法
    {% for foo in d.keys %}
        <p>{{ foo }}</p>
    {% endfor %}

    {% for value in d.values %}
        <p>{{ value }}</p>
    {% endfor %}

    {% for item in d.items %}
        <p>{{ item }}</p>
    {% endfor %}

# with起别名
    {% with d.hobby.2.info as nb %}
        <p>{{ nb }}</p>
        <p>在whit文法内可以通過as後面的别名使用到前面非常複雜的擷取資料方式</p>
    {% endwith %}

           

自定義過濾器、标簽、inclusion_tag

"""
先三步走
    1、在應用下面建立一個名字“必須”叫templatetages檔案夾
    2、在該檔案夾内建立“任意”名稱的py檔案 eg:mytag.py
    3、在該py檔案内“必須”先寫下面兩句話
        from django import template
        register = template.Library()
"""

# 1、自定義過濾器(參數最多兩個)
@register.filter(name='baby')
def my_sum(v1, v2):
    return v1 + v2
自定義的使用(過濾器最多隻能有兩個參數)
{% load mytag %}
<p>{{ n|baby:666 }}</p>


# 2、自定義标簽(參數可以多個)
@register.simple_tag(name='plus')
def index(a,b,c,d):
    return '%s-%s-%s-%s'%(a,b,c,d)
标簽多個參數彼此之間空格隔開
{% load mytag %}
<p>{% plus 'jason' 123 123 123 %}</p>


# 3、自定義inclusion_tag
"""
内部原理
    先定義一個方法
    在一面上調用方法,并可以傳值
    該方法會生成一些資料然後傳遞給一個html頁面
    之後将渲染好的結果放到調用位置
"""
# 自定義inclusion_tag
@register.inclusion_tag('left_menu.html')
def left(n):
    data = ['第{}項'.format(i) for i in range(n)]
    # return {'data':data}
    return locals()  # 将data傳遞給left_menu.html
使用:
{% left 10 %}
# 總結:當html頁面某一個地方的頁面需要傳參數才能動态渲染出來,并且在多個頁面上都需要使用該局部,那麼就考慮該局部頁面做成inclusion_tag形式
(在講bbs的時候使用到)           

模闆的繼承

模闆繼承,選選好一個想要繼承的模闆頁面

# 模闆的繼承
    {% extends 'bj_user.html' %}

# 繼承之後子頁面和模闆頁面長得一摸一樣,需要在模闆頁面上提前劃定可以被修改的區域
    {% block content  %}
    模闆的内容
    {% endblock %}

# 子頁面就可以聲明想要修改那塊決定的區域
    {% block content %}
        子頁面的内容
    {% endblock %}


# 一般情況下模闆頁面上至少有三塊可以修改的區域
    1、css區域
    2、html區域
    3、js區域
    # 這樣操作後,每個頁面就可以有自己獨有的css,html,js代碼
    
    
"""
一般情況下,模闆的頁面上劃定的區域越多,擴充性越高
如果太多,還不如自己寫
"""           

模闆的導入

"""
将頁面的某一個局部當成一個子產品的形式
那個地方需要直接導入即可
"""
<p>模闆的導入</p>
{% include 'bj_user.html' %}

           

django模型層

圖書管理系統

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

    # 書和出版社一對多
    publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE)
    # 和作者多對多
    author = models.ManyToManyField(to='Author')


class Publish(models.Model):
    name = models.CharField(max_length=32)
    addr = models.CharField(max_length=64)
    email = models.EmailField()  # 本質還是varchar(254),該字段是給校驗性元件看的


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()  # 電話号碼用BigIntegerField或者CharField
    addr = models.CharField(max_length=32)
           

單表操作

# django自帶的sqllite3資料庫對日期格式不是很敏感 處理的時候容易出錯

# 增
# res = models.user.objects.create(name='digua', age=18, register_time='2021-11-28')
# print(res)
# import datetime
# ctime = datetime.datetime.now()
# user_obj = models.user(name='egon', age=84, register_time=ctime)
# user_obj.save()


# 删
# res = models.user.objects.filter(pk=2).delete()
# print(res)
# user_obj = models.user.objects.filter(pk=1).first()
# user_obj.delete()
"""
pk會自動查找到目前表的主鍵字段,指代的就是目前表的主鍵
用了pk之後就不需要知道目前表的字段到底叫什麼
"""

# 修改
# models.user.objects.filter(pk=4).update(name='hongweidsb')
# user_obj = models.user.objects.get(pk=4)
# user_obj.name = 'egonPPP'
# user_obj.save()
# print(user_obj)
"""
get方法直接傳回的就是目前資料對象
該方法不推薦
一旦資料不存在,該方法會直接報錯而filter則不會,是以還是用filter
"""           

測試腳本

"""
當你隻是想測試django中某一個py檔案内容,那麼你可以不用書寫前後端互動模式,可以直接寫一個測試腳本
"""


from django.test import TestCase

# Create your tests here.


import os

if __name__ == '__main__':
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'djangoProject.settings')
    import django

    django.setup()

from app01 import models

models.User.objects.all()           

django終端答應sql語句

# 方式1
res3 = models.user.objects.values_list('name')
print(res3)
print(res3.query)
"""
# 檢視内部sql語句的方式,queryset對象才能狗點query檢視内部sql語句
"""

# 方式2:所有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',
        },
    }
}           

必知必會13條

必知必會n多條
# 1、all()       查詢所有資料
# 2、filter()    帶有過濾條件
# 3、get()       直接拿資料對象,但不存在會報錯
# 4、first()     拿queryset裡面的第一個元素
    res = models.user.objects.all().first()
    print(res)
# 5、last()    拿queryset對象裡最後一個元素
    res1 = models.user.objects.all().last()
    print(res1)
# 6、values()  篩選取值
    res2 = models.user.objects.values('name')
    print(res2)
    # 裡面是清單套字典
# 7、values_list()     篩選取值
    res3 = models.user.objects.values_list('name')
    print(res3)
# 8、distinct()      去重
    res = models.user.objects.all().distinct()
    print(res)
    需要将主鍵篩選走才能去重
    res = models.user.objects.values('name', 'age').distinct()
    print(res)
# 9、order_by()        排序
    res = models.user.objects.order_by('age')   # 預設升序
    res = models.user.objects.order_by('-age')   # 降序
    print(res)
# 10、reverse()        反轉,反轉的前提是資料已經排序
    res = models.user.objects.order_by('age')
    res1 = models.user.objects.order_by('age').reverse()
    print(res1)
# 11、count()          統計目前資料的個數
    res = models.user.objects.count()
    print(res)
# 12、exclude()        排除在外
    res = models.user.objects.exclude(name='json')
    print(res)
# 13、exists()         判斷某個東西是否存在
    res = models.user.objects.filter(pk=9).exists()
    print(res)
           

神奇的雙下劃線查詢

"""
# 神奇的雙下劃線查詢
        1、 年齡大于35歲的資料
            res = models.user.objects.filter(age__gt=35)
            print(res)
        2、 年齡小于35
            res = models.user.objects.filter(age__lt=35)
            print(res)
        3、 大于等于,小于等于
            res = models.user.objects.filter(age__gte=32)
            res = models.user.objects.filter(age__lte=32)
        4、 年齡是18 或者32 或者40
            res = models.user.objects.filter(age__in=[18,32,40])
            print(res)
        5、 年齡在18到40歲之間的
            res = models.user.objects.filter(age__range=[18,40])
            首尾都會取
        6、 模糊查詢,查詢出名字含有n的資料 模糊查詢,不忽略大小寫
            res = models.user.objects.filter(name__contains='n')
        7、 忽略大小寫
            res = models.user.objects.filter(name__icontains='D')
            print(res)
        8、以什麼開頭,什麼結尾的
            models.user.objects.filter(name__startswith='j')
            models.user.objects.filter(name__endswith='j')
        9、查詢出 注冊時間是2021年6月的資料,22年的資料
            res = models.user.objects.filter(register_time__month='6')
            res = models.user.objects.filter(register_time__year='2021')
            ...
"""

           

外鍵字段的增删改

"""
一對多的外鍵增删改查
        1、增
            1)直接寫實際字段id
                models.Book.objects.create(title='三國演繹', price=123.23, publish_id=1)
            2)虛拟字段,給資料對象
                publish_obj = models.Publish.objects.filter(pk=2).first()
                models.Book.objects.create(title='劍來', price=231.23, publish=publish_obj)
        
        2、删
            級聯删除
            models.Publish.objects.filter(pk=1).delete()
                
        3、修改
            1)直接寫id
            models.Book.objects.filter(pk=1).update(publish_id=2)
            2)傳對象
            obj = models.Publish.objects.filter(pk=1).first()
            models.Book.objects.filter(pk=1).update(publish=obj)
                
多對多外鍵增删改查(就是第三張關系表的增删改)
        1、如何給書籍綁定作者?(增加)
            1)放id
                # 先拿到一個書籍對象,裡有個authors外鍵屬性,點了authors之後就已經到了第三方關系表了
                book_obj = models.Book.objects.filter(pk=1).first()
                book_obj.author.add(1,2)      # 給書籍id為1的書籍綁定一個主鍵為1和2的作者
            2)放對象
                book_obj = models.Book.objects.filter(pk=1).first()
                author_obj = models.Author.objects.filter(pk=3).first()
                book_obj.author.add(author_obj)
            
        2、删除作者字段
            1)放id
                book_obj = models.Book.objects.filter(pk=1).first()
                book_obj.author.remove(3,2,1)  
                # 删除書主鍵為1,作者主鍵為3,2,1的這三條資料
            2)放對象
                book_obj = models.Book.objects.filter(pk=5).first()
                author_obj = models.Author.objects.filter(pk=3).first()
                book_obj.author.remove(author_obj)     
                # 删除主鍵為5的書的,作者主鍵為3的這條資料
            
        3、修改字段  set
            1)放id
                book_obj = models.Book.objects.filter(pk=2).first()
                book_obj.author.set([1,2])  # 括号内必須給一個可疊代對象
                # 将書id為2的資料删除,然後建立将書id為2的作者id改為1和2的兩條資料
                book_obj.author.set([3])
                # 将書id為2的資料删除,然後建立書為2作者id為3的資料

            2)放對象
                book_obj = models.Book.objects.filter(pk=6).first()
                author_obj = models.Author.objects.filter(pk=3).first()
                book_obj.author.set([author_obj])
                # 将書id為6的這條資料中的作者id改為3
        3、清空資料
            比如有本書下架了,我想将書籍和作者的綁定關系給清空
            book_obj = models.Book.objects.filter(pk=6).first()
            book_obj.author.clear()
            # 将主鍵為6的這本書和作者的所有關系清空掉,括号内不加參數
        
        
        
"""           

正反向概念

"""
一對一和多對多的正反向判斷:
正向
    看外鍵字段在哪一方
    書查出版社則外鍵在書手上,這就是正向

反向
    出版社查書,外鍵在書上,則這種為反向
"""



"""
正向查詢按字段
反向查詢按表名小寫


"""           

多表查詢

  • 子查詢(基于對象的跨表查詢)
子查詢就是分步查詢
"""
基于對象的跨表查詢
        1、查詢書籍主鍵為1的出版社  正向按字段
            book_obj = models.Book.objects.filter(pk=1).first()
            # 書查出版社  正向
            res = book_obj.publish
            # 書籍主鍵為1的書對應的出版對應東方出版社
            print(res)
            print(res.name)
            print(res.addr)
        2、查詢書籍主鍵為1的作者   書查作者外鍵在書,為正向,按字段
            book_obj = models.Book.objects.filter(pk=2).first()
            res = book_obj.author       # app01.Author.None
            res = book_obj.author.all()
            print(res)
            ps:如果結果為app01.Author.None,則需要.all()
        3、查詢作者hongwei的電話号碼  作者查作者詳情,正向
            author_obj = models.Author.objects.filter(name='hongwei').first()
            res = author_obj.author_detail  (當結果為一個對象的時候不需要.all)
            print(res)
            print(res.phone)
            print(res.addr)
            
        ps:正向什麼需要加.all
            當結果可能有多個的時候有.all
            如果隻有一個則不需要.all
            
        4、查詢出版社是東方出版社出版的書      出版社查書,反向,表名小寫
            publish_obj = models.Publish.objects.filter(name='東方出版社').first()
            res = publish_obj.book_set.all()
            print(res)
            
        5、查詢作者是hongwei寫過的書      作者查書,反向,表名小寫
            author_obj = models.Author.objects.filter(name='hongwei').first()
            res = author_obj.book_set.all()
            print(res)
            
        6、查詢手機号為110的作者姓名    作者詳情查作者,反向,表名小寫
            author_detail_obj = models.AuthorDetail.objects.filter(phone=110).first()
            res = author_detail_obj.author
            print(res.name)
            
        ps:反向什麼時候需要加_set.all()
            反向查詢的時候
                當你的查詢結果可以有多個的時候,就必須加_set.all()
                當你的結果隻有一個的時候,不需要加_set.all()
            
"""
           
  • 聯表查詢(基于雙下劃線的跨表查詢)
"""
基于雙下劃線的跨表查詢
        1、查詢hongwei的手機号和姓名
            res = models.Author.objects.filter(name='hongwei').values('author_detail__phone', 'name)
            print(res)
            反向,不允許點author
            # 拿作者是hongwei的作者詳情
            res = models.AuthorDetail.objects.filter(author__name='hongwei').values('phone','author__name')
            print(res)

        2、查詢書籍主鍵為1的出版社名稱和書的名稱   
            res = models.Book.objects.filter(pk=1).values('title', 'publish__name')
            print(res)
            反向:
            res = models.Publish.objects.filter(book__id=1).values('name','book__title')
            print(res)
        3、查詢書籍主鍵為1的作者姓名
            res = models.Book.objects.filter(pk=2).values('title','author__name')
            print(res)
            反向:
            res = models.Author.objects.filter(book__id=1).values('name', 'book__title')
            print(res)
            
        4、查詢書籍主鍵是1的作者的手機号
            res = models.Author.objects.filter(book__id=2).values('name','author_detail__phone')
            print(res)
            
            res = models.Book.objects.filter(pk=2).values('author__author_detail__phone')
            print(res)


隻要掌握了正反向概念以及雙下劃線
就能無限跨表
"""           

聚合查詢(聚合函數)

分組查詢(group by)annotate

F與Q查詢

django事務

orm中常用字段及參數

資料庫查詢優化

圖書管理系統案例