Django測(cè)試開(kāi)發(fā)學(xué)習(xí)筆記(一)

基礎(chǔ)介紹

1. 簡(jiǎn)介

Django担映,發(fā)音為[d???ɡ??],是用python語(yǔ)言寫(xiě)的開(kāi)源web開(kāi)發(fā)框架茧彤,并遵循MVC設(shè)計(jì)洋机。Django的主要目:簡(jiǎn)便、快速的開(kāi)發(fā)「數(shù)據(jù)庫(kù)」驅(qū)動(dòng)的網(wǎng)站贬媒。

學(xué)習(xí)網(wǎng)站:

官方網(wǎng)站: https://www.djangoproject.com/

github源碼:https://github.com/django/django

django中文文檔:https://yiyibooks.cn/xx/Django_1.11.6/index.html

2. 特點(diǎn)

  • 重量級(jí)框架

    對(duì)比Flask框架聋亡,Django原生提供了眾多的功能組件,讓開(kāi)發(fā)更簡(jiǎn)便快速际乘。

    • 提供項(xiàng)目工程管理 自動(dòng)化腳本工具

    • 數(shù)據(jù)庫(kù)ORM支持(對(duì)象關(guān)系映射坡倔,英語(yǔ):Object Relational Mapping)

    • 模板

    • 表單

    • Admin管理站點(diǎn)

    • 文件管理

    • 認(rèn)證權(quán)限

    • session機(jī)制

    • 緩存

  • MVT模式

    • M全拼為Model,與MVC中的M功能相同脖含,負(fù)責(zé)和數(shù)據(jù)庫(kù)交互罪塔,進(jìn)行數(shù)據(jù)處理。
    • V全拼為View养葵,與MVC中的C功能相同征堪,接收請(qǐng)求,進(jìn)行業(yè)務(wù)處理关拒,返回應(yīng)答佃蚜。
    • T全拼為T(mén)emplate,與MVC中的V功能相同着绊,負(fù)責(zé)封裝構(gòu)造要返回的html谐算。
    image
![image](https://upload-images.jianshu.io/upload_images/12041448-2817315ecaf2b5e8?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

3. 環(huán)境搭建

  • 環(huán)境準(zhǔn)備

    • python3.x
    • django 3.0.4
    • pycharm 專業(yè)版(專業(yè)版可以多一些django框架中界面操作的功能,社區(qū)版的話归露,需要用命令行去執(zhí)行)
  • 安裝django pip install django==3.0.4

4. 創(chuàng)建項(xiàng)目

  • 選擇django框架+虛擬環(huán)境


    image
  • 指定項(xiàng)目運(yùn)行的python解釋器
    Perference->Project Interpreter->選擇為虛擬環(huán)境中的python.exe

  • 項(xiàng)目中的文件

    • 最外層的:django_project: 項(xiàng)目的容器洲脂,可以隨便命名。
    • manage.py: 一個(gè)讓你用各種方式管理 Django 項(xiàng)目的命令行工具剧包。
    • django_project/init.py:一個(gè)空文件恐锦,告訴 Python 這個(gè)目錄應(yīng)該被認(rèn)為是一個(gè) Python 包雇毫。
    • django_project/settings.py:Django 項(xiàng)目的配置文件。
    • django_project/urls.py:Django 項(xiàng)目的 URL 聲明踩蔚,就像你網(wǎng)站的“目錄”。
    • django_project/wsgi.py:作為你的項(xiàng)目的運(yùn)行在 WSGI 兼容的Web服務(wù)器上的入口枚粘。
  • 啟動(dòng)命令配置

    image
![image](https://upload-images.jianshu.io/upload_images/12041448-e15f6482897c18db?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
  • 訪問(wèn)127.0.0.1:8000馅闽,表示環(huán)境搭建成功

    image

5. settings.py配置文件

  • app路徑配置

    INSTALLED_APPS = [
     'django.contrib.admin',
     'django.contrib.auth',
     'django.contrib.contenttypes',
     'django.contrib.sessions',
     'django.contrib.messages',
     'django.contrib.staticfiles',
     'app1.apps.App1Config', 
     # 默認(rèn)已有 如果沒(méi)有只要添加app名稱即可 例如: 'app1'
     # 新建的應(yīng)用都要在這里添加
    ]
    
  • 數(shù)據(jù)庫(kù)配置

    # 如果使用django的默認(rèn)sqlite3數(shù)據(jù)庫(kù)則不需要改
    DATABASES = {
     'default': {
     'ENGINE': 'django.db.backends.sqlite3',
     'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
     }
    }
    
    # 如果使用mysql數(shù)據(jù)庫(kù)需要將上述數(shù)據(jù)庫(kù)注掉修改如下:
    
    DATABASES = {
     'default': {  
     'ENGINE': 'django.db.backends.mysql',
     'NAME': 'blog', #你的數(shù)據(jù)庫(kù)名稱 數(shù)據(jù)庫(kù)需要自己提前建好
     'USER': 'root', #你的數(shù)據(jù)庫(kù)用戶名
     'PASSWORD': '', #你的數(shù)據(jù)庫(kù)密碼
     'HOST': '', #你的數(shù)據(jù)庫(kù)主機(jī),留空默認(rèn)為localhost
     'PORT': '3306', #你的數(shù)據(jù)庫(kù)端口
     }
    }
    
  • 靜態(tài)文件目錄

    STATIC_URL = ‘/static/’ #調(diào)用時(shí)目錄
    STATICFILES_DIRS=[
    os.path.join(BASE_DIR,“static”), #具體路徑
    ]
    
  • 中間件

    # 自己寫(xiě)的中間件馍迄,例如在項(xiàng)目中的md文件夾下md.py文件中的M1與M2兩個(gè)中間件
    
    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',
     'md.md.M1',
     'md.md.M2',
    ]
    # 注意自己寫(xiě)的中間件福也,配置要寫(xiě)在系統(tǒng)中的后面
    
  • session存儲(chǔ)的相關(guān)配置

    # 數(shù)據(jù)庫(kù)配置(默認(rèn))
    
    # Django默認(rèn)支持Session,并且默認(rèn)是將Session數(shù)據(jù)存儲(chǔ)在數(shù)據(jù)庫(kù)中攀圈,即:django_session 表中暴凑。
    # 配置 settings.py
     SESSION_ENGINE = 'django.contrib.sessions.backends.db' # 引擎(默認(rèn))
     SESSION_COOKIE_NAME = "sessionid"   # Session的cookie保存在瀏覽器上時(shí)的key,即:sessionid=隨機(jī)字符串(默認(rèn))
     SESSION_COOKIE_PATH = "/"    # Session的cookie保存的路徑(默認(rèn))
     SESSION_COOKIE_DOMAIN = None    # Session的cookie保存的域名(默認(rèn))
     SESSION_COOKIE_SECURE = False    # 是否Https傳輸cookie(默認(rèn))
     SESSION_COOKIE_HTTPONLY = True    # 是否Session的cookie只支持http傳輸(默認(rèn))
     SESSION_COOKIE_AGE = 1209600    # Session的cookie失效日期(2周)(默認(rèn))
     SESSION_EXPIRE_AT_BROWSER_CLOSE = False   # 是否關(guān)閉瀏覽器使得Session過(guò)期(默認(rèn))
     SESSION_SAVE_EVERY_REQUEST = False   # 是否每次請(qǐng)求都保存Session赘来,默認(rèn)修改之后才保存(默認(rèn))
     
     SESSION_CACHE_ALIAS = 'default' # 使用緩存的別名现喳,此處設(shè)置成redis數(shù)據(jù)庫(kù)配置的別名default
    
    
  • 緩存配置

    • 內(nèi)存緩存配置

      # 配置緩存
       CACHES = {
       'default': {
        'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
        'LOCATION': 'unix:/tmp/memcached.sock',
        'KEY_PREFIX': 'lcfcn',
        'TIMEOUT': None
          }
       }
      
    • 文件緩存配置

      CACHES = {
          'default': {
              'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
              'LOCATION': '/var/tmp/django_cache', # 文件路徑
          }
      }
      
    • 數(shù)據(jù)庫(kù)緩存配置

      CACHES = {
          'default': {
              'BACKEND': 'django.core.cache.backends.db.DatabaseCache',
              'LOCATION': 'my_cache_table', # 數(shù)據(jù)庫(kù)表名,任意名字即可
          }
      }
      

      配置完之后記得在cmd中執(zhí)行下列語(yǔ)句創(chuàng)建緩存表

      python manage.py createcachetable

    • redis緩存配置

      CACHES = { # 配置緩存數(shù)據(jù)為redis
          "default": {
              "BACKEND": "django_redis.cache.RedisCache",
              "LOCATION": "redis://127.0.0.1:6379",
              "OPTIONS": {
                  "CLIENT_CLASS": "django_redis.client.DefaultClient",
                  "PASSWORD":"12345"
              }
          }
      }
      
    • CACHES設(shè)置中有幾個(gè)額外的參數(shù):

      • TIMEOUT:緩存超時(shí)時(shí)間犬辰,默認(rèn)為300s嗦篱,可以設(shè)置為None,即永不超時(shí)幌缝。

      • OPTIONS : locmem, filesystem和database緩存系統(tǒng)這些有自己的剔除策略的系統(tǒng)有以下的參數(shù):

      • MAX_ENTRIES : 緩存中存放的最大條目數(shù)灸促,大于這個(gè)數(shù)時(shí),舊的條目將會(huì)被刪除涵卵,默認(rèn)為300.

      • CULL_FREQUENCY:當(dāng)達(dá)到MAX_ENTRIES的時(shí)候,被接受的訪問(wèn)的比率浴栽。實(shí)際的比率是1/cull_frequency,所以設(shè)置為2就是在達(dá)到max_entries時(shí)去除一半數(shù)量的緩存,設(shè)置為0意味著達(dá)到max_entries時(shí),緩存將被清空轿偎。這個(gè)值默認(rèn)是3典鸡。

      • KEY_PREFIX:一個(gè)會(huì)自動(dòng)列入緩存key值的的字符串。

      • VERSION:緩存key值生成時(shí)使用的版本數(shù)字贴硫。

      • KEY_FUNCTION:key值最終生成所使用的方法椿每。

6. Django常用命令

  • 創(chuàng)建項(xiàng)目

    django-admin startproject project_name

  • 新建app

    cd 項(xiàng)目根目錄

    python manage.py startapp app_name

  • 創(chuàng)建數(shù)據(jù)庫(kù)表 或 更改數(shù)據(jù)庫(kù)表或字段

    生成遷移腳本 python manage.py makemigrations

    執(zhí)行遷移腳本 python manage.py migrate

  • 使用開(kāi)發(fā)服務(wù)器

    開(kāi)發(fā)服務(wù)器,即開(kāi)發(fā)時(shí)使用英遭,一般修改代碼后會(huì)自動(dòng)重啟间护,方便調(diào)試和開(kāi)發(fā),但是由于性能問(wèn)題挖诸,建議只用來(lái)測(cè)試汁尺,不要用在生產(chǎn)環(huán)境。

    python manage.py runserver

    當(dāng)提示端口被占用的時(shí)候多律,可以用其它端口:

    python manage.py runserver 8001

    監(jiān)聽(tīng)機(jī)器所有可用 ip (電腦可能有多個(gè)內(nèi)網(wǎng)ip或多個(gè)外網(wǎng)ip)

    python manage.py runserver 0.0.0.0:8000

    如果是外網(wǎng)或者局域網(wǎng)電腦上可以用其它電腦查看開(kāi)發(fā)服務(wù)器

    訪問(wèn)對(duì)應(yīng)的ip加端口痴突,比如 http://172.16.20.2:8000

  • 清空數(shù)據(jù)庫(kù)

    python manage.py flush

    此命令會(huì)詢問(wèn)是 yes 還是 no, 選擇 yes 會(huì)把數(shù)據(jù)全部清空掉搂蜓,只留下空表。

  • 創(chuàng)建超級(jí)管理員

    python manage.py createsuperuser

    按照提示輸入用戶名和對(duì)應(yīng)的密碼就好了郵箱可以留空辽装,用戶名和密碼必填

    修改用戶密碼可以用:

    python manage.py changepassword username

  • 導(dǎo)出數(shù)據(jù) 導(dǎo)入數(shù)據(jù)

    python manage.py dumpdata appname > appname.json

    python manage.py loaddata appname.json

  • Django 項(xiàng)目環(huán)境終端

    python manage.py shell

    如果你安裝了 bpython 或 ipython 會(huì)自動(dòng)用它們的界面帮碰,推薦安裝 bpython。

    這個(gè)命令和 直接運(yùn)行 python 或 bpython 進(jìn)入 shell 的區(qū)別是:你可以在這個(gè) shell 里面調(diào)用當(dāng)前項(xiàng)目的 models.py 中的 API拾积,對(duì)于操作數(shù)據(jù)殉挽,還有一些小測(cè)試非常方便。

  • 數(shù)據(jù)庫(kù)命令行
    python manage.py dbshell

    Django 會(huì)自動(dòng)進(jìn)入在settings.py中設(shè)置的數(shù)據(jù)庫(kù)拓巧,如果是 MySQL 或 postgreSQL,會(huì)要求輸入數(shù)據(jù)庫(kù)用戶密碼斯碌。

    在這個(gè)終端可以執(zhí)行數(shù)據(jù)庫(kù)的SQL語(yǔ)句。如果您對(duì)SQL比較熟悉肛度,可能喜歡這種方式傻唾。

  • 反向生成model

    python manage.py inspectdb

  • 更多命令

    python manage.py

    可以看到詳細(xì)的列表,在忘記子名稱的時(shí)候特別有用承耿。

視圖

1. 視圖函數(shù)

  • 介紹

    一個(gè)視圖函數(shù)冠骄,簡(jiǎn)稱視圖,是一個(gè)簡(jiǎn)單的Python函數(shù)加袋,它接受Web請(qǐng)求并且返回Web響應(yīng)猴抹。響應(yīng)可以是一張網(wǎng)頁(yè)的HTML內(nèi)容,一個(gè)重定向锁荔,一個(gè)404錯(cuò)誤蟀给,一個(gè)XML文檔,或者一張圖片阳堕,是任何東西都可以跋理。無(wú)論視圖本身包含什么邏輯,都要返回響應(yīng)恬总。代碼寫(xiě)在哪里也無(wú)所謂前普,只要它在你的Python目錄下面。除此之外沒(méi)有更多的要求了——可以說(shuō)“沒(méi)有什么神奇的地方”壹堰。為了將代碼放在某處拭卿,約定是將視圖放置在項(xiàng)目或應(yīng)用程序目錄中的名為views.py的文件中。

    視圖函數(shù):

    一定包含兩個(gè)對(duì)象:

    • request---->用戶請(qǐng)求相關(guān)的所有信息(對(duì)象)

    • Httpresponse---->響應(yīng)字符串

  • 簡(jiǎn)單的視圖demo

    from django.http import HttpResponse # 導(dǎo)入了HttpResponse類
    
    # 我們定義了hello_world函數(shù)贱纠。它就是視圖函數(shù)峻厚。
    # 每個(gè)視圖函數(shù)都使用HttpRequest對(duì)象作為第一個(gè)參數(shù),并且通常稱之為 request谆焊。
    def helloworld(request):
        return HttpResponse("helloworld!hello,測(cè)開(kāi)大佬!")
    
  • 配置路由

    主路由惠桃,即項(xiàng)目下的urls.py

    from django.contrib import admin
    from django.urls import path, include
    
    urlpatterns = [
        path('admin/', admin.site.urls),
        path('test/',include('views_demo.urls'))
    ]
    

    子路由,即app下的urls.py

    from django.urls import path
    from views_demo import views
    
    urlpatterns = [
        path('helloworld/',views.helloworld),
    ]
    
  • 根據(jù)路由訪問(wèn)示例

    image

    展示了views.py中定義的helloworld函數(shù)的返回

2. 請(qǐng)求和響應(yīng)

視圖函數(shù),圍繞著兩個(gè)對(duì)象進(jìn)行:HttpResponse和HttpRequest

  • HttpRequest

    request---->請(qǐng)求信息

    request.path # 獲取訪問(wèn)文件路徑
    
    request.method屬性 #獲取請(qǐng)求中使用的HTTP方式(POST/GET)
    
    request.body #含所有請(qǐng)求體信息 是bytes類型
    
    request.GET #GET請(qǐng)求的數(shù)據(jù)(類字典對(duì)象)  請(qǐng)求頭中的url中?后面拿值
    
    request.POST # POST請(qǐng)求的數(shù)據(jù)(類字典對(duì)象) 請(qǐng)求體里拿值
    
    request.COOKIES #包含所有cookies的標(biāo)準(zhǔn)Python字典對(duì)象辜王;keys和values都是字符串劈狐。
    
    request.FILES:包含所有上傳文件的類字典對(duì)象;FILES中的每一個(gè)Key都是<input type="file" name=""/>標(biāo)簽中name屬性的值呐馆,F(xiàn)ILES中的每一個(gè)value同時(shí)也是一個(gè)標(biāo)準(zhǔn)的python字典對(duì)象肥缔,包含下面三個(gè)Keys:
        - filename:上傳文件名,用字符串表示
        - content_type:上傳文件的Content Type
        - content:上傳文件的原始內(nèi)容
    
    request.user:是一個(gè)django.contrib.auth.models.User對(duì)象汹来,代表當(dāng)前登陸的用戶辫继。如果訪問(wèn)用戶當(dāng)前沒(méi)有登陸,user將被初始化為django.contrib.auth.models.AnonymousUser的實(shí)例俗慈。你可以通過(guò)user的is_authenticated()方法來(lái)辨別用戶是否登陸:if req.user.is_authenticated();只有激活Django中的AuthenticationMiddleware時(shí)該屬性才可用
    
    request.session:唯一可讀寫(xiě)的屬性,代表當(dāng)前會(huì)話的字典對(duì)象遣耍;自己有激活Django中的session支持時(shí)該屬性才可用
    
    request.GET.get('name') 拿到GET請(qǐng)求里name的值
    
    如果某個(gè)鍵對(duì)應(yīng)有多個(gè)值闺阱,則不能直接用get取值,需要用getlist舵变,如:request.POST.getlist("hobby")
    
    請(qǐng)求url:http://127.0.0.1:8000/index.html/23?a=1
    
    request.path : 請(qǐng)求路徑
    request.path結(jié)果為:/index.html/23
    
    request.get_full_path()
    request.get_full_path()結(jié)果為:/index.html/23?a=1
    

    可以自己在視圖函數(shù)中打印下試試酣溃,可在控制臺(tái)看到:

    def helloworld(request):
        print(request.path)
        print(request.GET)
        print(request.body)
        return HttpResponse("helloworld!hello,測(cè)開(kāi)大佬!")
    
  • HttpResponse

    HttpResponse---->響應(yīng)字符串

    對(duì)于HttpRequest請(qǐng)求對(duì)象來(lái)說(shuō),是由django自動(dòng)創(chuàng)建的纪隙,但是赊豌,HttpResponse響應(yīng)對(duì)象就必須我們自己創(chuàng)建。每個(gè)view請(qǐng)求處理方法必須返回一個(gè)HttpResponse響應(yīng)對(duì)象绵咱。HttpResponse類在django.http.HttpResponse碘饼。

    常用屬性:

    content:返回的內(nèi)容。
    response = HttpResponse()
    response.content = '果芽軟件'
    return response
    status_code:返回的HTTP響應(yīng)狀態(tài)碼
    content_type:返回?cái)?shù)據(jù)的mime類型
    

    常用方法:

    set_cookie:用來(lái)設(shè)置cookie信息
    delete_cookie:用來(lái)刪除cookie信息悲伶。
    write:HttpResponse是一個(gè)類似于文件的對(duì)象艾恼,可以用來(lái)寫(xiě)入數(shù)據(jù)到數(shù)據(jù)體(content)中。
    
  • JsonResponse對(duì)象

    # 把字典或者列表當(dāng)做抓換成json數(shù)據(jù)并返回
    
    def test_redirect(request):
        return JsonResponse([{"code":0000,"msg":'成功'}],safe=False) # 數(shù)據(jù)類型為列表麸锉,必須指定safe=False
        # return JsonResponse({"code":0000,"msg":'成功'},safe=False) # 數(shù)據(jù)類型為字典钠绍,不必指定safe
    
  • 其他常用響應(yīng)函數(shù)和對(duì)象

    • render 函數(shù)(前后端分離開(kāi)發(fā),不需要掌握花沉,了解即可)

      將指定頁(yè)面渲染后返回給瀏覽器

      render(request, template_name[, context])

      結(jié)合一個(gè)給定的模板和一個(gè)給定的上下文字典柳爽,并返回一個(gè)渲染后的 HttpResponse 對(duì)象。

    • redirect 函數(shù)

      參數(shù)可以是:

      一個(gè)模型:將調(diào)用模型的get_absolute_url() 函數(shù)
      一個(gè)視圖碱屁,可以帶有參數(shù):將使用urlresolvers.reverse 來(lái)反向解析名稱
      一個(gè)絕對(duì)的或相對(duì)的URL磷脯,將原封不動(dòng)的作為重定向的位置。

      默認(rèn)返回一個(gè)臨時(shí)的重定向娩脾;傳遞permanent=True 可以返回一個(gè)永久的重定向争拐。

3. 類視圖

>以函數(shù)的形式進(jìn)行定義的視圖就是函數(shù)視圖,視圖函數(shù)便于理解,但是遇到一個(gè)視圖函數(shù)對(duì)應(yīng)的路徑提供了多種不同的HTTP請(qǐng)求方式的支持時(shí)(get,post,delete,put),需要在一個(gè)函數(shù)中寫(xiě)不同的業(yè)務(wù)邏輯,代碼的可讀性和復(fù)用性就很低, 所以,我們引入類視圖進(jìn)行解決。
  • 未使用類視圖

     def register(request):
        """處理注冊(cè)"""
     
        # 獲取請(qǐng)求方法,判斷是GET/POST請(qǐng)求
        if request.method == 'GET':
            # 處理GET請(qǐng)求架曹,返回注冊(cè)頁(yè)面
            return render(request, 'register.html')
        else:
            # 處理POST請(qǐng)求隘冲,實(shí)現(xiàn)注冊(cè)邏輯
            return HttpResponse('這里實(shí)現(xiàn)注冊(cè)邏輯')
    
  • 使用類視圖示例

    class DefineClassview(View):
        """演示類視圖的定義和使用"""
    
        def get(self, request):
            """處理GET請(qǐng)求業(yè)務(wù)邏輯"""
            return HttpResponse('GET請(qǐng)求業(yè)務(wù)邏輯')
    
        def post(self, request):
            """處理POST請(qǐng)求業(yè)務(wù)邏輯"""
            return HttpResponse('POST請(qǐng)求業(yè)務(wù)邏輯')
    
        def put(self, request):
            pass
    
  • 類視圖的使用

    • 定義類視圖需要繼承自的Django提供的父類的View

    • 導(dǎo)入

      • from django.views.generic import View
    • 示例 :views.py

      from django.http import HttpResponse
      from django.views import View #導(dǎo)入View
      class ViewDemo(View):
      
          def get(self,request):
              return HttpResponse("get方法被調(diào)用")
      
          def post(self,request):
              return HttpResponse("post方法被調(diào)用")
      
          def put(self,request):
              return HttpResponse("put方法被調(diào)用")
      
          def delete(self,request):
              return HttpResponse("delete方法被調(diào)用")
      
    • 配置路由時(shí),需要使用類視圖的as_view()方法來(lái)注冊(cè)添加

      urlpatterns = [
      path('',view.ViewDemo.as_view()),# 使用as_view()方法把類視圖注冊(cè)為視圖
      ]
      
    • 去掉禁用跨域訪問(wèn)的中間件

      若接口返回403 Forbidden,注釋掉settings.py中的禁用跨域訪問(wèn)的中間件

      image

路由

1. 單一路由

就是一個(gè)路徑對(duì)應(yīng)一個(gè)視圖函數(shù)或者視圖類

```
urlpatterns = [
    path('hello/',view.hello_world),
    path('',view.ViewDemo.as_view()),# 使用as_view()方法把類視圖注冊(cè)為視圖
]
```

2. 基于正則的路由

前邊的寫(xiě)法绑雄,我們?cè)谠L問(wèn)一個(gè)接口的時(shí)候展辞,接口地址最后邊必須要帶一個(gè)/但是這樣看著極度不美觀。我們就可以通過(guò)基于正則表達(dá)式的路由幫我們解決万牺。

注意:

  • 基于正則表達(dá)式的路由必須使用re_path而不是我們之前用的path了
  • 正則表達(dá)式字符串的開(kāi)頭字母“r”罗珍。它告訴Python這是個(gè)原始字符串,不需要處理里面的反斜杠(轉(zhuǎn)義字符)(2.0版本之后可以不用帶了)

    urlpatterns = [
        re_path(r'^hello.?$',view.ViewDemo.as_view()),# .?代表0到1個(gè)任意字符脚粟,這樣寫(xiě)我們?cè)谠L問(wèn)地址的時(shí)候就可以省略最后邊的/了
    ]
    

3. 路由參數(shù)傳遞

  • 在Django中路由參數(shù)傳遞改變了一點(diǎn)寫(xiě)法

    urlpatterns = [
        path("args/<pk>/",view.args_demo),# 默認(rèn)是匹配字符串
    ]
    
  • 視圖函數(shù)參數(shù)列表中需要變量來(lái)接收url參數(shù)覆旱,且視圖中的參數(shù)和上邊的關(guān)鍵字一致

    def args_demo(request,pk):# 視圖函數(shù)的參數(shù)列表中需要一個(gè)變量來(lái)接收url參數(shù)
        print(pk)
        return HttpResponse("pk的值為:{}".format(pk))
    
  • 注意:

    • 要捕獲一段url中的值,需要使用尖括號(hào)
    • 可以轉(zhuǎn)換捕獲到的值為指定類型核无,比如例子中的int扣唱。默認(rèn)情況下,捕獲到的結(jié)果保存為字符串類型团南,不包含/這個(gè)特殊字符噪沙;
  • 還可以寫(xiě)成正則表達(dá)式的形式

    urlpatterns = [
        re_path(r"^args/(?P<pk>[a-zA-Z]+).?$",view.args_demo) # 正則表達(dá)式的寫(xiě)法,
    ]
    
    # (?P<關(guān)鍵字>) 指定正則表達(dá)式提取值的存放關(guān)鍵字
    # [a-zA-Z]+  表示匹配1到多個(gè)字母 匹配內(nèi)容根據(jù)你正則表達(dá)式來(lái)定
    # (?P<pk>[a-zA-Z]+) 完整的解釋就是匹配1到多個(gè)字母,存入pk這個(gè)關(guān)鍵字中
    
  • url參數(shù)轉(zhuǎn)換器


    image
    urlpatterns = [
        path("args/<int:pk>/",view.args_demo),# 表示匹配 int類型的參數(shù)
    ]
    
  • 傳遞多個(gè)參數(shù)

    path("args/<int:page>/<int:size>/",view.args_demo)
    
  • 視圖函數(shù)中也要對(duì)應(yīng)聲明多個(gè)參數(shù)來(lái)接收

    def args_demo(request,page,size):# 視圖函數(shù)的參數(shù)列表中需要一個(gè)變量來(lái)接收url參數(shù)
        return HttpResponse("page的值為:{},size的值為:{}".format(page,size))
    
  • 參數(shù)傳遞默認(rèn)值

    path("args/<int:page>/<int:size>/",view.args_demo,{"page":1,"size":5})
    

4. 路由分發(fā)

路由分發(fā)指的是一個(gè)請(qǐng)求過(guò)來(lái)之后吐根,怎么通過(guò)一級(jí)一級(jí)的轉(zhuǎn)發(fā)正歼,給到對(duì)應(yīng)的程序處理;在django中一般指的是拷橘,從主app分發(fā)到子app中

  • 創(chuàng)建子應(yīng)用

    python manage.py startapp app01

  • settings.py中引入剛創(chuàng)建的app

image
  • 子應(yīng)用中創(chuàng)建子路由文件
image
  • 子應(yīng)用中寫(xiě)一個(gè)視圖和路由信息局义,方便講路由分發(fā)

views.py

from django.http import HttpResponse
from django.shortcuts import render

# Create your views here.

def hello_world(request):

    return HttpResponse('hello world')

urls.py

from django.urls import path, re_path

from . import views

urlpatterns = [
    re_path(r"^hello.?$",views.hello_world),
]
  • 使用include分發(fā)路由
from django.urls import path, re_path, include

from django_project import view

urlpatterns = [
    path("v01/",include("app01.urls")) # 主路由中使用include轉(zhuǎn)發(fā)至子路由中
]
  • 重啟服務(wù)之后,瀏覽器訪問(wèn)

5. url反向解析和命名空間(這個(gè)部分沒(méi)懂冗疮,待補(bǔ)充旭咽,0524路由&視圖)

在實(shí)際開(kāi)發(fā)中,系統(tǒng)內(nèi)部某些視圖會(huì)通過(guò)redirect(url)重定向至其他的視圖來(lái)處理赌厅,但是如果url地址被改掉了穷绵,我們通過(guò)url重定向就會(huì)失敗,為了解決這個(gè)問(wèn)題特愿,引入了命名路由和命名空間的概念

ORM

  • ORM 概念

對(duì)象關(guān)系映射(Object Relational Mapping仲墨,簡(jiǎn)稱ORM)模式是一種為了解決面向?qū)ο笈c關(guān)系數(shù)據(jù)庫(kù)存在的互不匹配的現(xiàn)象的技術(shù)。 簡(jiǎn)單的說(shuō)揍障,ORM是通過(guò)使用描述對(duì)象和數(shù)據(jù)庫(kù)之間映射的元數(shù)據(jù)目养,將程序中的對(duì)象自動(dòng)持久化到關(guān)系數(shù)據(jù)庫(kù)中。 ORM在業(yè)務(wù)邏輯層和數(shù)據(jù)庫(kù)層之間充當(dāng)了橋梁的作用

  • ORM 由來(lái)

讓我們從O/R開(kāi)始毒嫡。字母O起源于"對(duì)象"(Object)癌蚁,而R則來(lái)自于"關(guān)系"(Relational)。 幾乎所有的軟件開(kāi)發(fā)過(guò)程中都會(huì)涉及到對(duì)象和關(guān)系數(shù)據(jù)庫(kù)。在用戶層面和業(yè)務(wù)邏輯層面努释,我們是面向?qū)ο蟮摹?當(dāng)對(duì)象的信息發(fā)生變化的時(shí)候碘梢,我們就需要把對(duì)象的信息保存在關(guān)系數(shù)據(jù)庫(kù)中。 按照之前的方式來(lái)進(jìn)行開(kāi)發(fā)就會(huì)出現(xiàn)程序員會(huì)在自己的業(yè)務(wù)邏輯代碼中夾雜很多SQL語(yǔ)句用來(lái)增加伐蒂、讀取煞躬、修改、刪除相關(guān)數(shù)據(jù)逸邦, 而這些代碼通常都是極其相似或者重復(fù)的

  • ORM 優(yōu)勢(shì)

ORM解決的主要問(wèn)題是對(duì)象和關(guān)系的映射恩沛。它通常將一個(gè)類和一張表一一對(duì)應(yīng),類的每個(gè)實(shí)例對(duì)應(yīng)表中的一條記錄缕减, 類的每個(gè)屬性對(duì)應(yīng)表中的每個(gè)字段雷客。 ORM提供了對(duì)數(shù)據(jù)庫(kù)的映射,不用直接編寫(xiě)SQL代碼桥狡,只需操作對(duì)象就能對(duì)數(shù)據(jù)庫(kù)操作數(shù)據(jù)搅裙。 讓軟件開(kāi)發(fā)人員專注于業(yè)務(wù)邏輯的處理,提高了開(kāi)發(fā)效率总放。

  • ORM 劣勢(shì)

ORM的缺點(diǎn)是會(huì)在一定程度上犧牲程序的執(zhí)行效率。 ORM的操作是有限的好爬,也就是ORM定義好的操作是可以完成的局雄,一些復(fù)雜的查詢操作是完成不了。 ORM用多了SQL語(yǔ)句就不會(huì)寫(xiě)了存炮,關(guān)系數(shù)據(jù)庫(kù)相關(guān)技能退化…

  • ORM 總結(jié)

ORM只是一種工具炬搭,工具確實(shí)能解決一些重復(fù),簡(jiǎn)單的勞動(dòng)穆桂。這是不可否認(rèn)的宫盔。 但我們不能指望某個(gè)工具能一勞永逸地解決所有問(wèn)題,一些特殊問(wèn)題還是需要特殊處理的享完。 但是在整個(gè)軟件開(kāi)發(fā)過(guò)程中需要特殊處理的情況應(yīng)該都是很少的灼芭,否則所謂的工具也就失去了它存在的意義。

  • ORM 與 DB 的對(duì)應(yīng)關(guān)系

ORM 面向?qū)ο蠛完P(guān)系型數(shù)據(jù)庫(kù)的一種映射,通過(guò)操作對(duì)象的方式操作數(shù)據(jù)庫(kù)數(shù)據(jù),不支持對(duì)庫(kù)的操作,只能操作表 對(duì)應(yīng)關(guān)系: 類 --> 表 對(duì)象 --> 數(shù)據(jù)行 屬性 --> 字段

Model 模塊 在Django中model是你數(shù)據(jù)的單一般又、明確的信息來(lái)源彼绷。它包含了你存儲(chǔ)的數(shù)據(jù)的重要字段和行為。通常茴迁, 一個(gè)模型(model)映射到一個(gè)數(shù)據(jù)庫(kù)表寄悯。

  • 基本情況:

每個(gè)模型都是一個(gè)Python類,它是django.db.models.Model的子類堕义。模型的每個(gè)屬性都代表一個(gè)數(shù)據(jù)庫(kù)字段猜旬。
綜上所述,Django為您提供了一個(gè)自動(dòng)生成的數(shù)據(jù)庫(kù)訪問(wèn)API,詳詢官方文檔

1. 安裝mysql

2. django連接配置數(shù)據(jù)庫(kù)

  • mysql中新建一個(gè)數(shù)據(jù)庫(kù)

  • 安裝msyql client

    pip install mysqlclient==1.4.6

  • settings.py文件中配置數(shù)據(jù)庫(kù)鏈接信息

    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.mysql',
            'HOST': '127.0.0.1',  # 數(shù)據(jù)庫(kù)主機(jī)
            'PORT': 3306,  # 數(shù)據(jù)庫(kù)端口
            'USER': 'root',  # 數(shù)據(jù)庫(kù)用戶名
            'PASSWORD': 'root',  # 數(shù)據(jù)庫(kù)用戶密碼
            'NAME': 'test'  # 數(shù)據(jù)庫(kù)名字
        }
    }
    
  • 檢查是否配置成功

    • pycharm terminal中執(zhí)行python manage.py dbshell
    • 可進(jìn)入mysql虛擬終端洒擦,表示配置成功

3. ORM表模型

定義模型

在Django中椿争,所有的模型必須繼承from django.db.models import Model這個(gè)類,字段類型需要使用models模塊中定義好的字段類型

from django.db import models

class Student(models.Model):  # 一個(gè)類對(duì)應(yīng)一個(gè)表

# 類屬性對(duì)應(yīng)表中的字段秘遏,models.CharField這里對(duì)應(yīng)字段的類型丘薛,這個(gè)是字符串類型
# max_length定義字段的最大長(zhǎng)度
# 五大約束:非空約束(null=False,為默認(rèn),可不寫(xiě))、主鍵約束(primary_key=True)邦危、唯一約束(unique=True)洋侨、可空(null=True)、外鍵約束(通過(guò)models.ForeignKey()來(lái)指定)
# help_text添加該字段的備注信息倦蚪,但沒(méi)有加在數(shù)據(jù)庫(kù)中希坚,讓自己看著比較清楚
# choices=((0, '男'), (1, '女')),表示該字段只有0陵且,1兩個(gè)值裁僧,0代表男,1代表女
#  models.DateTimeField 該字段是日期類型
# auto_now_add=True 在每一次數(shù)據(jù)被添加進(jìn)去的時(shí)候慕购,記錄當(dāng)前時(shí)間
# auto_now=True 在每一次數(shù)據(jù)被保存的時(shí)候聊疲,記錄當(dāng)前時(shí)間
    
    s_name = models.CharField(max_length=64,help_text="學(xué)生姓名")
    s_sex = models.IntegerField(choices=((0, '男'), (1, '女')), help_text="性別")
    s_phone = models.CharField(max_length=11, help_text="手機(jī)號(hào)")
    create_time = models.DateTimeField(auto_now_add=True)
    
    update_time = models.DateTimeField(auto_now=True)

    class Meta:
        db_table = 'student'  # 指定表名,如果不指定表名沪悲,會(huì)用app名+類名生成表名


下圖是mysql數(shù)據(jù)庫(kù)字段和Models中定義類型的關(guān)系


image
模型中常用屬性
image
django提供的一些特殊屬性
EmailField(CharField):
    - 字符串類型获洲,Django Admin以及ModelForm中提供驗(yàn)證機(jī)制
    - e_mail = models.EmailField(max_length=255, unique=True)

IPAddressField(Field)
    - 字符串類型,Django Admin以及ModelForm中提供驗(yàn)證 IPV4 機(jī)制

GenericIPAddressField(Field)
    - 字符串類型殿如,Django Admin以及ModelForm中提供驗(yàn)證 Ipv4和Ipv6
    - 參數(shù):
        protocol贡珊,用于指定Ipv4或Ipv6, 'both',"ipv4","ipv6"
        unpack_ipv4涉馁, 如果指定為T(mén)rue门岔,則輸入::ffff:192.0.2.1時(shí)候,可解析為192.0.2.1烤送,開(kāi)啟此功能寒随,需要protocol="both"

URLField(CharField)
    - 字符串類型,Django Admin以及ModelForm中提供驗(yàn)證 URL

SlugField(CharField)
    - 字符串類型帮坚,Django Admin以及ModelForm中提供驗(yàn)證支持 字母牢裳、數(shù)字、下劃線叶沛、連接符(減號(hào))

CommaSeparatedIntegerField(CharField)
    - 字符串類型蒲讯,格式必須為逗號(hào)分割的數(shù)字

UUIDField(Field)
    - 字符串類型,Django Admin以及ModelForm中提供對(duì)UUID格式的驗(yàn)證

FilePathField(Field)
    - 字符串灰署,Django Admin以及ModelForm中提供讀取文件夾下文件的功能
    - 參數(shù):
            path,                      文件夾路徑
            match=None,                正則匹配
            recursive=False,           遞歸下面的文件夾
            allow_files=True,          允許文件
            allow_folders=False,       允許文件夾

FileField(Field)
    - 字符串判帮,路徑保存在數(shù)據(jù)庫(kù)局嘁,文件上傳到指定目錄
    - 參數(shù):
        upload_to = ""      上傳文件的保存路徑
        storage = None      存儲(chǔ)組件携茂,默認(rèn)django.core.files.storage.FileSystemStorage

ImageField(FileField)
    - 字符串务荆,路徑保存在數(shù)據(jù)庫(kù),文件上傳到指定目錄
    - 參數(shù):
        upload_to = ""      上傳文件的保存路徑
        storage = None      存儲(chǔ)組件纯丸,默認(rèn)django.core.files.storage.FileSystemStorage
        width_field=None,   上傳圖片的高度保存的數(shù)據(jù)庫(kù)字段名(字符串)
        height_field=None   上傳圖片的寬度保存的數(shù)據(jù)庫(kù)字段名(字符串)
自定義字段(了解即可)

示例:我們發(fā)現(xiàn)上邊沒(méi)有固定長(zhǎng)度的字符串類型晌畅,但是手機(jī)號(hào)字段一般都是定長(zhǎng)11位的字符串但指,所以我們需要自定義一些字段類型



from django.db import models

# Create your models here.

class PhoneField(models.Field):  # 自定義的char類型的字段類

    def __init__(self, max_length, *args, **kwargs):
        self.max_length = max_length
        super(PhoneField, self).__init__(max_length=max_length, *args, **kwargs)

    def db_type(self, connection):  # 限定生成數(shù)據(jù)庫(kù)表的字段類型為char,長(zhǎng)度為max_length指定的值的字符串
        return 'char(%s)' % self.max_length
Field的常用參數(shù)
image
模型中Meta配置:

對(duì)于一些模型級(jí)別的配置抗楔。我們可以在模型中定義一個(gè)類棋凳,叫做Meta。然后在這個(gè)類中添加一些類屬性來(lái)控制模型的作用连躏。

比如我們想要在數(shù)據(jù)庫(kù)映射的時(shí)候使用自己指定的表名剩岳,而不是使用模型的名稱。那么我們可以在Meta類中添加一個(gè)db_table的屬性入热。示例代碼如下:

class Book(models.Model):
    name = models.CharField(max_length=20,null=False)
    desc = models.CharField(max_length=100,name='description',db_column="description1")

    class Meta:
        db_table = 'book_model'
image
外鍵和表關(guān)系

4. ORM模型遷移

生成遷移腳本
  • python manage.py makemigrations
![image](https://upload-images.jianshu.io/upload_images/12041448-8322b9155e8bc7fa?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
  • 會(huì)在model_demo下的migrations文件夾下生成一個(gè)0001_initial.py文件,如下:

    from django.db import migrations, models
    
    
    class Migration(migrations.Migration):
    
        initial = True
    
        dependencies = [
        ]
    
        operations = [
            migrations.CreateModel(
                name='Student',
                fields=[
                    ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                    ('s_name', models.CharField(help_text='學(xué)生姓名', max_length=64)),
                    ('s_sex', models.IntegerField(choices=[(0, '男'), (1, '女')], help_text='性別')),
                    ('s_phone', models.CharField(help_text='手機(jī)號(hào)', max_length=11)),
                    ('create_time', models.DateTimeField(auto_now_add=True)),
                    ('update_time', models.DateTimeField(auto_now=True)),
                ],
                options={
                    'db_table': 'student',
                },
            ),
        ]
    
    

    比我們自己寫(xiě)的model,多了一個(gè)id字段拍棕,這是django自動(dòng)生成的,對(duì)所有的表都會(huì)添加這樣一個(gè)字段勺良,所以不用特別去定義绰播。

    遷移腳本生成時(shí),數(shù)據(jù)庫(kù)還沒(méi)有這個(gè)表尚困。

執(zhí)行遷移標(biāo)本蠢箩,數(shù)據(jù)庫(kù)中創(chuàng)建新表
  • python manage.py migrate
image

因?yàn)橹斑€做了別的操作,只想執(zhí)行model_demo下的遷移腳本尾组,所以可以在命令后面加上app的名字忙芒。

在數(shù)據(jù)庫(kù)中創(chuàng)建了student表示弓,django_migrations表存儲(chǔ)了的是django的遷移記錄讳侨。

image
image

可以看看這些字段的約束和我們定義的一樣:

image
遷移命令詳解
  • makemigrations:將模型生成遷移腳本。模型所在的app奏属,必須放在settings.py中的INSTALLED_APPS中跨跨。這個(gè)命令有以下幾個(gè)常用選項(xiàng):

    • app_label:后面可以跟一個(gè)或者多個(gè)app,那么就只會(huì)針對(duì)這幾個(gè)app生成遷移腳本囱皿。如果沒(méi)有任何的app_label勇婴,那么會(huì)檢查INSTALLED_APPS中所有的app下的模型,針對(duì)每一個(gè)app都生成響應(yīng)的遷移腳本嘱腥。

    • -name:給這個(gè)遷移腳本指定一個(gè)名字耕渴。

    • -empty:生成一個(gè)空的遷移腳本。如果你想寫(xiě)自己的遷移腳本齿兔,可以使用這個(gè)命令來(lái)實(shí)現(xiàn)一個(gè)空的文件橱脸,然后自己再在文件中寫(xiě)遷移腳本础米。

  • migrate:將新生成的遷移腳本。映射到數(shù)據(jù)庫(kù)中添诉。創(chuàng)建新的表或者修改表的結(jié)構(gòu)屁桑。以下一些常用的選項(xiàng):

    • app_label:將某個(gè)app下的遷移腳本映射到數(shù)據(jù)庫(kù)中。如果沒(méi)有指定栏赴,那么會(huì)將所有在INSTALLED_APPS中的app下的模型都映射到數(shù)據(jù)庫(kù)中蘑斧。
      app_label migrationname:將某個(gè)app下指定名字的migration文件映射到數(shù)據(jù)庫(kù)中。
    • –fake:可以將指定的遷移腳本名字添加到數(shù)據(jù)庫(kù)中须眷。但是并不會(huì)把遷移腳本轉(zhuǎn)換為SQL語(yǔ)句竖瘾,修改數(shù)據(jù)庫(kù)中的表。
    • –fake-initial:將第一次生成的遷移文件版本號(hào)記錄在數(shù)據(jù)庫(kù)中柒爸。但并不會(huì)真正的執(zhí)行遷移腳本准浴。
  • showmigrations:查看某個(gè)app下的遷移文件。如果后面沒(méi)有app捎稚,那么將查看INSTALLED_APPS中所有的遷移文件乐横。

  • sqlmigrate:查看某個(gè)遷移文件在映射到數(shù)據(jù)庫(kù)中的時(shí)候,轉(zhuǎn)換的SQL語(yǔ)句今野。

5. abstract創(chuàng)建模型父類

在創(chuàng)建模型的時(shí)候葡公,其實(shí)有好多字段都是模型中共同存在的,例如createtime,updatetime,mark等等条霜,這些字段我們需要在每個(gè)模型中重復(fù)創(chuàng)建催什,這就造成了工作量的浪費(fèi),我們可以通過(guò)創(chuàng)建一個(gè)公共的模型父類來(lái)宰睡,子類集成該父類蒲凶,這樣我們就不需要重復(fù)寫(xiě)這些字段了

class PublicModel(models.Model):
    createtime = models.DateTimeField(auto_now_add=True,verbose_name="創(chuàng)建日期")
    updatetime = models.DateTimeField(auto_now=True,verbose_name = '修改日期')
    status = models.IntegerField(verbose_name = '狀態(tài)')
    class Meta:
        abstract=True  # 父類中必須指定該屬性,否則該類會(huì)被創(chuàng)建到數(shù)據(jù)庫(kù)


# 子類繼承PublicModel類拆内,就不需要重復(fù)寫(xiě)createtime,update,status三個(gè)字段的定義了
class Student(PublicModel):
    s_name = models.CharField(max_length=64,help_text="學(xué)生姓名")
    s_sex = models.IntegerField(choices=((0, '男'), (1, '女')), help_text="性別")
    s_phone = models.CharField(max_length=11, help_text="手機(jī)號(hào)")

    class Meta:
        db_table = 'student'
  • model修改旋圆,重新遷移
    • 刪掉migrations文件夾下遷移腳本
    • 刪掉django_migrations表中的遷移記錄
    • 刪掉student表
    • 重新生成遷移腳本
    • 執(zhí)行遷移腳本

6. ORM操作

ORM操作準(zhǔn)備
  • 以這個(gè)模型來(lái)進(jìn)行后續(xù)的ORM操作練習(xí)

    class Student(models.Model):  
        s_name = models.CharField(max_length=64,help_text="學(xué)生姓名")
        s_sex = models.IntegerField(choices=((0, '男'), (1, '女')), help_text="性別")
        s_phone = models.CharField(max_length=11, help_text="手機(jī)號(hào)")
        create_time = models.DateTimeField(auto_now_add=True)
        update_time = models.DateTimeField(auto_now=True)
    
        class Meta:
            db_table = 'student'  
    
  • 進(jìn)入django的虛擬終端

    image
  • 導(dǎo)入要操作的模型類

    image
新增數(shù)據(jù)
  • 插入單條數(shù)據(jù)-save
    s = Student(s_name="李白",s_sex=0,s_phone='18103909786')
    s.save()
    
![image](https://upload-images.jianshu.io/upload_images/12041448-51f8e1f7d480c0a8?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

數(shù)據(jù)庫(kù)新增了一條記錄:

![image](https://upload-images.jianshu.io/upload_images/12041448-294c9a2b6642c6f2?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
  • 插入單條數(shù)據(jù)-create

    使用模型對(duì)象(objects)操作數(shù)據(jù)庫(kù)

    Student.objects.create(s_name='魯班七號(hào)',s_sex=0,s_phone='15855586589')
    
    image

    數(shù)據(jù)庫(kù)新增了一條記錄:


    image
  • 批量插入多條數(shù)據(jù)-bulk_create

    s1 = Student(s_name="王二錘",s_sex=0,s_phone='18103909782')
    s2 = Student(s_name="王三錘",s_sex=0,s_phone='18103909783')
    s3 = Student(s_name="王四錘",s_sex=0,s_phone='18103909784')
    
    student_list = [s1,s2,s3]
    Student.objects.bulk_create(student_list)
    

    數(shù)據(jù)庫(kù)新增了多條數(shù)據(jù):

    image
查找數(shù)據(jù)

查找數(shù)據(jù)都是通過(guò)模型下的objects對(duì)象來(lái)實(shí)現(xiàn)的

  • 查找所有數(shù)據(jù)

    使用Student.objects.all()student表的所有數(shù)據(jù),等同于select * from student

    image

    通過(guò)上邊的例子我們可看出麸恍,我們使用Student.objects.all()方法查詢出了數(shù)據(jù)所有的數(shù)據(jù)灵巧,返回了一個(gè)QuerySet的list對(duì)象,list里邊存的都是Student對(duì)象抹沪,所以我們可以通過(guò)students[0]拿到list中第一個(gè)Student對(duì)象刻肄,然后通過(guò)Student.s_name就可以查看Student對(duì)象中,s_name的值同理融欧,我們可以用類似的方法查看s_sex,s_phone的值

數(shù)據(jù)過(guò)濾
  • 單條件過(guò)濾

    在查找數(shù)據(jù)的時(shí)候敏弃,有時(shí)候需要對(duì)一些數(shù)據(jù)進(jìn)行過(guò)濾。那么這時(shí)候需要調(diào)用objects的filter方法噪馏。

    類似與sql語(yǔ)句中的where麦到,查詢出s_name='魯班七號(hào)'的數(shù)據(jù)虹茶,返回的是一個(gè)list,所以需要加上下標(biāo)訪問(wèn)隅要。

    image

    搜索出來(lái)的結(jié)果返回是一個(gè)QuerySet蝴罪,QuerySet常用的內(nèi)置方法values()first()

![image](https://upload-images.jianshu.io/upload_images/12041448-6a67a6b89e507f30?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

`values()`展示詳細(xì)的數(shù)據(jù)步清,更易讀
`first()` 展示第一條數(shù)據(jù)
  • 其他過(guò)濾條件(雙下劃線查詢)

    # 查詢姓名中包含'二'字的學(xué)生信息
    s = Student.objects.filter(s_name__contains='王')
    s[0].s_name
    
    # 查詢id>2的學(xué)生信息
    s=Student.objects.filter(id__gt=2).values()
    s
    
    image
![image](https://upload-images.jianshu.io/upload_images/12041448-92b1ad44c8ac97fe?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

常用的符號(hào)

![image](https://upload-images.jianshu.io/upload_images/12041448-b2798ac9c8f03abb?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
  • 日期過(guò)濾

    settings.py文件中修改USE_TZ = False

    # 查詢?nèi)掌谑?020-07-05創(chuàng)建的用戶
    s=Student.objects.filter(create_time__date='2020-07-05')
    
    image
  • 日期的比較

    # 查詢2020-07-05 00:00:00之后創(chuàng)建的用戶
    import datetime
    date = datetime.datetime(2020,4,2)
    student = Student.objects.filter(create_time__gte=date)
    
其他查詢方式
  • get查詢

    獲取滿足條件的一個(gè)數(shù)據(jù)要门,獲取不到或者多個(gè)都報(bào)錯(cuò)。一般通過(guò)主鍵查詢廓啊。

    s = Student.objects.get(pk=1) 欢搜,pk就是主鍵的意思,可以看到get方法返回的是一個(gè)Student對(duì)象

    image
  • exclude

    獲取不滿足條件的所有數(shù)據(jù)谴轮,exclude返回的是一個(gè)QuerySet類型的對(duì)象列表

    # 獲取主鍵不等于1的所有數(shù)據(jù)
    s = Student.objects.exclude(pk=1)
    
    image
  • values

    查詢的對(duì)象轉(zhuǎn)為字典炒瘟。

    s = Student.objects.exclude(pk=1) # 先根據(jù)條件篩選出部分?jǐn)?shù)據(jù),返回結(jié)果是一個(gè)QuerySet類型的對(duì)象列表
    s.values('s_name','s_sex') # 再使用values()確定展示字段
    Student.objects.values('s_name','s_sex') # #查詢出全部數(shù)據(jù)第步,并確定展示字段
    
    image
  • values_list()

    它與values()非常相似疮装,它返回的是一個(gè)元組序列,相對(duì)字典要節(jié)省空間粘都。

    Student.objects.values_list('s_name','s_sex')
    
    image
  • first

    取第一條元素廓推。沒(méi)有元素返回None,有返回第一條記錄翩隧。相當(dāng)于Student.objects.exclude(pk=1)[0]樊展,但是Student.objects.exclude(pk=1)[0]沒(méi)有值時(shí)會(huì)報(bào)錯(cuò)。

    Student.objects.exclude(pk=1).first()

  • last

    取最后一條元素堆生。沒(méi)有元素返回None专缠,有返回最后一條記錄。與first同理

    Student.objects.exclude(pk=1).last()
    
  • exists

    如果QuerySet包含數(shù)據(jù)淑仆,就返回True涝婉,否則返回False

    Student.objects.filter(pk=1).exists()
    
  • 嵌套查詢

    -- 查詢性別和id=2的學(xué)生相同的所有學(xué)生信息
    SELECT * from student where s_sex in (SELECT s_sex from student where id=2)
    

    ORM實(shí)現(xiàn):

    student=Student.objects.filter(pk=2)
    Student.objects.filter(s_sex=student[0].s_sex)
    
![image](https://upload-images.jianshu.io/upload_images/12041448-a93aa961db53fe28?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
  • F查詢

    (針對(duì)自己?jiǎn)伪碇凶侄蔚谋容^和處理)

    在上面所有的例子中,我們構(gòu)造的過(guò)濾器都只是將字段值與某個(gè)常量做比較糯景。如果我們要對(duì)兩個(gè)字段的值做比較嘁圈,那該怎么做呢省骂?

    # 查詢創(chuàng)建之后被修改了的用戶信息
    from django.db.models import F
    Student.objects.filter(update_time__gt=F("create_time"))
    
多條件查詢
  • 并列關(guān)系

    filter默認(rèn)就是并列關(guān)系,逗號(hào)分割就是并列關(guān)系

    Student.objects.filter(s_name='魯班七號(hào)',s_sex=0)
    
    image
  • Q查詢

    使用Q查詢蟀淮,先要導(dǎo)入Q查詢模塊

    from django.db.models import Q
    
    • &

      stu=Student.objects.filter(Q(s_name='魯班七號(hào)')&Q(s_sex=0))
      
      image
- 或 `|`
    ```
    # 篩選s_name='魯班七號(hào)'或者s_sex=1
    stu=Student.objects.filter(Q(s_name='魯班七號(hào)')|Q(s_sex=1))
    ```

    ![image](https://upload-images.jianshu.io/upload_images/12041448-05954b20d16bdd4c?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

- 非 `~`
    ```
    stu=Student.objects.filter(~Q(s_sex=0))
    ```


    ![image](https://upload-images.jianshu.io/upload_images/12041448-502a2ec8d476aa90?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
數(shù)據(jù)聚合-aggregate

sql中聚合函數(shù)有:max()、min()钞澳、count()怠惶、avg()、sum(),在ORM中如何表示轧粟?

使用聚合函數(shù)對(duì)數(shù)據(jù)進(jìn)行統(tǒng)計(jì)操作策治,就需要使用到aggregate方法,返回的是一個(gè)字典脓魏。

aggregate是從整個(gè)查詢結(jié)果集生成統(tǒng)計(jì)數(shù)據(jù)。

  • 導(dǎo)入聚合函數(shù)的類

    from django.db.models import Avg, Sum, Max, Min, Count
    
  • 用法:先篩選通惫,再聚合

    image
  • 修改字段名

    image
排序

排序使用order_by()

image

# 按id字段正序排列茂翔,默認(rèn)為正序,由小到大
stu=Student.objects.filter(Q(s_name='魯班七號(hào)')|Q(s_sex=0)).order_by("id")
# 按id字段倒序排列履腋,加個(gè)符號(hào)
stu=Student.objects.filter(Q(s_name='魯班七號(hào)')|Q(s_sex=0)).order_by("-id")
數(shù)據(jù)去重

去重使用.valuse("去重字段").distinct

# s_sex字段去重
stu=Student.objects.filter(s_sex=0).values("s_sex").distinct()
image
分頁(yè)

使用django自帶的分頁(yè)器Paginator來(lái)對(duì)數(shù)據(jù)進(jìn)行分頁(yè)操作

  • 導(dǎo)入分頁(yè)器

    from django.core.paginator import Paginator
    
  • 分頁(yè)

    # 導(dǎo)入模塊
    from django.core.paginator import Paginator
    # Paginator第一個(gè)參數(shù)是要分頁(yè)的數(shù)據(jù)珊燎,第二個(gè)參數(shù)per_page是每頁(yè)的數(shù)據(jù)條數(shù)
    p = Paginator(Student.objects.all(),per_page=2)
    # get_page()表示獲取第幾頁(yè)的數(shù)據(jù),返回一個(gè)Page對(duì)象遵湖,object_list獲取對(duì)象中的數(shù)據(jù)列表
    print(p.get_page(1).object_list)
    

    當(dāng)獲取的頁(yè)數(shù)悔政,沒(méi)有數(shù)據(jù)時(shí),會(huì)返回最后一頁(yè)的數(shù)據(jù)延旧。

    image
    # 判斷是否有下一頁(yè),有下一頁(yè)返回True谋国,沒(méi)有返回False
    p.page(1).has_next()
    
    image
    # 判斷是否有前一頁(yè)
    p.page(1).has_previous()
    

    其他的一些分頁(yè)操作:

    image
分組
  • sq中的分組

    select s_sex,count(*) from student group by s_sex;
    

    sql中的分組有語(yǔ)法約定,展示的字段迁沫,只能是被分組的字段和聚合函數(shù)芦瘾。

    在ORM中,我們也是重點(diǎn)關(guān)注集畅,展示字段分組字段

  • ORM的分組

    Student.objects.all().values('s_sex').annotate(Count('id')).values('s_sex','id__count')
    

    第一個(gè).values('s_sex')是確定分組的字段旅急,annotate(Count('id'))是聚合函數(shù),.values('s_sex','id__count')是展示字段牡整,回想之前學(xué)習(xí)Count時(shí)藐吮,count('id'),返回的字段是id__count,所以這里展示字段要寫(xiě)id__count

![image](https://upload-images.jianshu.io/upload_images/12041448-a9aed20f130328f8?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

所以,它還可以這樣寫(xiě)逃贝,使用`count=Count('id')`
```
Student.objects.all().values('s_sex').annotate(count=Count('id')).values('s_sex','count')
```
![image](https://upload-images.jianshu.io/upload_images/12041448-5221b6a94c135025?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
  • having怎么實(shí)現(xiàn)

    在annotate之后使用filter谣辞,相當(dāng)于having

    Student.objects.all().values('s_sex').annotate(count=Count('id')).filter(count=1).values('s_sex')
    
    image
修改數(shù)據(jù)

get和filter查詢出來(lái)的數(shù)據(jù)結(jié)構(gòu)不一樣,get查詢出來(lái)的結(jié)果是一個(gè)對(duì)象沐扳,filter泥从、exclude等查詢出來(lái)的結(jié)果是一個(gè)查詢集,他們的修改操作是不一樣的沪摄。

  • 對(duì)對(duì)象的修改操作

    # 把id=3的性別改為1
    stu=Student.objects.get(id=3) # stu是一個(gè)對(duì)象
    stu.s_sex=1 # 修改對(duì)象中的屬性值躯嫉,此時(shí),數(shù)據(jù)庫(kù)值還沒(méi)有改變
    stu.save() # 使用.save()來(lái)觸發(fā)對(duì)數(shù)據(jù)庫(kù)的操作
    
  • 對(duì)查詢集的修改操作

    #  把性別為1的學(xué)生手機(jī)號(hào)改為13800000000
    student=Student.objects.filter(s_sex=1) # student是一個(gè)查詢集
    student.update(s_phone='13800000000') # 使用.update()來(lái)修改值
    # 修改多個(gè)值使用逗號(hào)分割
    student.update(s_phone='13800000000',s_name='王小二')
    
    image
刪除數(shù)據(jù)

在查找到數(shù)據(jù)后杨拐,便可以進(jìn)行刪除了祈餐。刪除數(shù)據(jù)非常簡(jiǎn)單,只需要調(diào)用這個(gè)對(duì)象的delete方法即可哄陶。

stu = Student.objects.get(id='6')
stu.delete()
  • 物理刪除&邏輯刪除

    image
事務(wù)和回滾
  • 什么是事務(wù)和回滾

    事務(wù):多個(gè)數(shù)據(jù)邏輯操作的集合

    回滾:多個(gè)邏輯中某個(gè)操作出錯(cuò)帆阳,回到初始狀態(tài)

    事務(wù)的原子性要求事務(wù)要么全部完成,要么全部不完成屋吨,不可能停滯在某個(gè)中間狀態(tài)

  • 什么情況下需要使用事務(wù)

    修改多個(gè)ORM模型做時(shí)需要使用事務(wù)和回滾操作

    對(duì)結(jié)果要求嚴(yán)格一致(要么全部成功蜒谤,要么全部失斏奖觥)

  • django中怎么使用事務(wù)

    • 自動(dòng)進(jìn)行事務(wù)提交和回滾
      # 自動(dòng)進(jìn)行事務(wù)提交和回滾
      
      from django.db import transaction
      
      # 使用@transaction.atomic實(shí)現(xiàn)自動(dòng)進(jìn)行事務(wù)提交和回滾
      @transaction.atomic
      def test(request):
          # 事務(wù)提交
          Student.objects.filter(id=1).update(s_sex=1) # 若沒(méi)有事務(wù),這次操作是會(huì)成功的
          stu = Student.objects.get(id=0) # 查詢不到id=0的學(xué)生鳍徽,get方法會(huì)報(bào)錯(cuò)
          stu.s_sex=1
          stu.save()
          Student.objects.filter(id=2).update(s_sex=1)# 失敗
          return HttpResponse("ok")
          
      def test(request):
          # 使用上下文管理器實(shí)現(xiàn)自動(dòng)進(jìn)行事務(wù)提交和回滾
          with transaction.atomic():
              Student.objects.get(id=1).update(s_sex=1) # 若沒(méi)有事務(wù)资锰,這次操作是會(huì)成功的
              stu = Student.objects.get(id=0) # 查詢不到id=0的學(xué)生,get方法會(huì)報(bào)錯(cuò)
              stu.s_sex=1
              stu.save()
              Student.objects.filter(id=2).update(s_sex=1)# 失敗
              return HttpResponse("ok")
      
    • 手動(dòng)進(jìn)行事務(wù)提交和回滾
      # 手動(dòng)進(jìn)行事務(wù)提交和回滾
      def test(request):
      # 事務(wù)提交
          try:
              transaction.set_autocommit(False)# 關(guān)閉django自動(dòng)提交
              Student.objects.get(id=1).update(s_sex=1) # 若沒(méi)有事務(wù)阶祭,這次操作是會(huì)成功的
              stu = Student.objects.get(id=0) # 查詢不到id=0的學(xué)生台妆,get方法會(huì)報(bào)錯(cuò)
              stu.s_sex=1
              stu.save()
              Student.objects.filter(id=2).update(s_sex=1)# 失敗
              transaction.commit() # 操作成功,事務(wù)提交
          except:
              print("操作失敗胖翰,事務(wù)回滾")
              transaction.rollback()  # 操作失敗接剩,事務(wù)回滾
              return HttpResponse("ok")
      

7. ORM多表關(guān)聯(lián)

image
關(guān)聯(lián)關(guān)系
  • 一對(duì)一

    student <----> student_info

  • 多對(duì)一

    score --------> student

    score --------> course

    course --------> teacher

  • 多對(duì)多

    student <----------------------> course

關(guān)聯(lián)模型創(chuàng)建
  • 一對(duì)一 models.OneToOneField()

    關(guān)聯(lián)關(guān)系放在使用頻率較高的表

    image
  • 多對(duì)一 models.ForeignKey()

    關(guān)聯(lián)關(guān)放在“多”的表里

    image
  • 多對(duì)多 models.ManyToManyField()

    關(guān)聯(lián)關(guān)放在使用頻率較高的表

![image](https://upload-images.jianshu.io/upload_images/12041448-9c7c7f28130527bb?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
  • 關(guān)系表級(jí)聯(lián)刪除 on_delete

    image
代碼示例

models.py

from django.db import models


# Create your models here.

# 學(xué)生表
class Stu(models.Model):
    s_name = models.CharField('學(xué)生姓名', max_length=64, null=False, help_text='學(xué)生姓名')
    s_sex = models.IntegerField('性別', max_length=1, choices=((0, '男'), (1, '女')), help_text='性別')
    s_age = models.PositiveIntegerField('年齡', null=False, default=0, help_text='年齡')
    s_dept = models.CharField("專業(yè)", max_length=64, null=False, help_text="專業(yè)")
    # 一對(duì)一關(guān)系,用models.OneToOneField(),關(guān)聯(lián)放在使用頻率較高的表中
    """
        models.OneToOneField()有三個(gè)參數(shù):
            to:設(shè)置要關(guān)聯(lián)的表名(類),
            to_field:設(shè)置要關(guān)聯(lián)的表字段(類屬性),
            on_delete:當(dāng)關(guān)聯(lián)字段刪除時(shí)萨咳,s_id的值設(shè)置成什么懊缺,常用設(shè)置為models.CASCADE,表示當(dāng)關(guān)聯(lián)字段刪除時(shí)培他,它也刪除
    """
    """
        related_name:一般可以使用當(dāng)前表_關(guān)聯(lián)表來(lái)命名
            正向查詢時(shí)鹃两,通過(guò)s_id可以查詢student_info表中的數(shù)據(jù),
            反向查詢(從student_info表查詢student表數(shù)據(jù)時(shí))使用related_name進(jìn)行查詢
    """
    # db_column指定表字段列名
    si_id = models.OneToOneField(to='StudentInfo', to_field="id", on_delete=models.CASCADE, db_column='si_id',
                                 related_name="stu_stu_info")
    
    # 多對(duì)多關(guān)系會(huì)自動(dòng)生成一張中間表舀凛,db_table是對(duì)中間表的命名
    course = models.ManyToManyField(to="Course", db_table="stu_course", related_name="course_student")

    class Meta:
        db_table = 'stu'

# 學(xué)生信息表
class StudentInfo(models.Model):
    s_card = models.CharField("身份證號(hào)", max_length=18, null=False, unique=True)
    s_phone = models.CharField(max_length=11, null=False, unique=True, help_text="手機(jī)號(hào)")
    s_addr = models.CharField("家庭住址", max_length=128, help_text="家庭住址")

    class Meta:
        db_table = "student_info"

# 課程表
class Course(models.Model):
    c_name = models.CharField('課程名',max_length=64,null=False,help_text="課程名")
    t_id = models.ForeignKey(to="Teacher",to_field="id",on_delete=models.CASCADE,related_name='teacher_course',db_column='t_id',help_text="老師編號(hào)")

    class Meta:
        db_table="course"

# 成績(jī)表
class Score(models.Model):
    s_id = models.ForeignKey(to="Stu", to_field="id", on_delete=models.CASCADE, related_name='stu_score',
                             db_column='s_id', help_text="學(xué)生編號(hào)")
    c_id = models.ForeignKey(to="Course", to_field="id", on_delete=models.CASCADE, related_name='course_score',
                             db_column='c_id', help_text="學(xué)生編號(hào)")
    score = models.PositiveIntegerField("成績(jī)",null=False,default=0,help_text="成績(jī)")

    class Meta:
        db_table = "score"

# 老師表
class Teacher(models.Model):
    t_name = models.CharField("老師姓名", max_length=64,null=False,help_text="老師姓名")

    class Meta:
        db_table = "teacher"

數(shù)據(jù)遷移:

python manage.py makemigrations
python manage.py migrate multi_table
關(guān)聯(lián)模型操作

增刪改俊扳,都是單表操作,只有查詢涉及多表猛遍,我們就主要講下查詢的多表操作

  • 數(shù)據(jù)準(zhǔn)備

    -- 數(shù)據(jù)準(zhǔn)備sql 
    insert into `student_info` (`id`, `s_card`, `s_phone`, `s_addr`) values('1','410422200205061358','18103909786','河南省魯山縣');
    insert into `student_info` (`id`, `s_card`, `s_phone`, `s_addr`) values('2','310112199003074772','13853444534','上海閔行區(qū)');
    insert into `student_info` (`id`, `s_card`, `s_phone`, `s_addr`) values('3','31011520020907641X','15520979867','上海市浦東新區(qū)');
    
    insert into `stu` (`id`, `s_name`, `s_sex`, `s_age`, `s_dept`, `si_id`) values('2','薛小磊','0','18','計(jì)算機(jī)科學(xué)','1');
    insert into `stu` (`id`, `s_name`, `s_sex`, `s_age`, `s_dept`, `si_id`) values('3','王大錘','1','30','生物科學(xué)','2');
    insert into `stu` (`id`, `s_name`, `s_sex`, `s_age`, `s_dept`, `si_id`) values('4','薛大磊','0','18','外貿(mào)金融','3');
    
    insert into `teacher` (`id`, `t_name`) values('1','張三');
    insert into `teacher` (`id`, `t_name`) values('2','李四');
    insert into `teacher` (`id`, `t_name`) values('3','王五');
    
    insert into `course` (`id`, `c_name`, `t_id`) values('1','數(shù)學(xué)','1');
    insert into `course` (`id`, `c_name`, `t_id`) values('2','語(yǔ)文','2');
    insert into `course` (`id`, `c_name`, `t_id`) values('3','英語(yǔ)','3');
    
    insert into `score` (`id`, `score`, `c_id`, `s_id`) values('1','80','1','2');
    insert into `score` (`id`, `score`, `c_id`, `s_id`) values('2','90','2','2');
    insert into `score` (`id`, `score`, `c_id`, `s_id`) values('3','85','3','2');
    insert into `score` (`id`, `score`, `c_id`, `s_id`) values('4','60','1','3');
    insert into `score` (`id`, `score`, `c_id`, `s_id`) values('5','55','2','3');
    insert into `score` (`id`, `score`, `c_id`, `s_id`) values('6','70','3','3');
    insert into `score` (`id`, `score`, `c_id`, `s_id`) values('7','30','1','4');
    insert into `score` (`id`, `score`, `c_id`, `s_id`) values('8','50','2','4');
    

    tips:當(dāng)模型改變時(shí)馋记,需要刷新一下Python Console

    image
  • 新增數(shù)據(jù)

    學(xué)生表和中間表stu_course是多對(duì)多的關(guān)系,中間表是django自動(dòng)生成的懊烤,是沒(méi)有數(shù)據(jù)的梯醒。中間表的數(shù)據(jù),只能通過(guò)一張表來(lái)生成另一張表的數(shù)據(jù)腌紧,我們從stu表生成stu_course表的數(shù)據(jù)茸习。

    # 查詢出一條數(shù)據(jù),返回結(jié)果是Stu對(duì)象
    stu = Stu.objects.filter(s_name='薛小磊').first()
    # 使用add方法往第三張表中添加三條和薛小磊關(guān)聯(lián)的數(shù)據(jù)壁肋,`.course`是字段名
    # 通過(guò)stu_id增加course_id号胚,stu_id=2的學(xué)生,選了3門(mén)課浸遗,課程id是1猫胁,2,3
    stu.course.add(1,2,3)
    # stu_id為3的學(xué)生乙帮,選了課程id是2杜漠,3的兩門(mén)課
    Stu.objects.get(pk=3).course.add(2,3)
    Stu.objects.get(pk=4).course.add(1,2)
    
    image
  • 刪除數(shù)據(jù)

    # 查詢出一條數(shù)據(jù)
    stu = Stu.objects.filter(s_name='薛小磊').first()
    # 使用remove方法刪除中間表中的和薛小磊關(guān)聯(lián)的數(shù)據(jù)
    stu.course.remove(1,2,3)
    
  • 重置數(shù)據(jù)

    #無(wú)則加极景,有則刪除
    stu = Stu.objects.filter(s_name='薛小磊').first()
    # 添加編號(hào)2 3的選課記錄
    stu.course.add(2, 3)
    # 使用set方法重置選課記錄為1,3
    stu = Stu.objects.filter(s_name='薛小磊').first()
    stu.course.set([1,3])
    
  • 清空

    # 清空薛小磊所有的選課記錄
    stu = Stu.objects.filter(s_name='薛小磊').first()
    stu.course.clear()
    
  • 一對(duì)一查詢

    # 導(dǎo)入model
    from multi_table.models import Stu
    from multi_table.models import StudentInfo
    
    # 正向查詢:關(guān)聯(lián)student_info表查詢第一條學(xué)生的身份證號(hào)
    student=Stu.objects.first()
    stu_detail=student.si_id
    stu_detail.s_card
    
    image
    # 反向查詢:查詢身份證號(hào)為410422200205061358的學(xué)生姓名
    stu_info=StudentInfo.objects.filter(s_card='410422200205061358').first()
    stu=stu_info.stu_stu_info # 通過(guò)related_name進(jìn)行反向查詢
    stu.s_name
    
    image
  • 多對(duì)一查詢

    # 導(dǎo)入model
    from multi_table.models import Course
    from multi_table.models import Teacher
    
    # 正向查詢:通過(guò)課程表查找任課老師
    course=Course.objects.filter(c_name='語(yǔ)文').first()
    teacher=course.t_id
    teacher.t_name
    
    image
    # 反向查詢
    
    # 通過(guò)通過(guò)related_name進(jìn)行反向查詢察净,course返回了一個(gè)model的對(duì)象
    course=Teacher.objects.first().teacher_course 
    # 對(duì)象轉(zhuǎn)為查詢集
    courses=course.all() 
    # 通過(guò)for循環(huán)編輯結(jié)果
    for c in courses:
        print(c.c_name)
    
    
![image](https://upload-images.jianshu.io/upload_images/12041448-80e0c140a41b85fe?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
  • 多對(duì)多

    # 多對(duì)多正向查詢- 根據(jù)屬性course查詢
    
    # 查詢 薛小磊同學(xué)選修的課程名
    stu = Stu.objects.filter(s_name='薛小磊').first()
    courses = stu.course.all()
    for c in courses:
        print(c.c_name)
    
    # 多對(duì)多反向查詢-根據(jù)related_name查詢
    
    # 查詢選修了數(shù)學(xué)課程的學(xué)生姓名
    course = Course.objects.filter(c_name='數(shù)學(xué)').first()
    students = course.course_student.all()
    for s in students:
        print(s.s_name)
    

8. QuerySet常用API

我們通常做查詢操作的時(shí)候驾茴,都是通過(guò)模型名字.objects的方式進(jìn)行操作。其實(shí)模型名字.objects是一個(gè)django.db.models.manager.Manager對(duì)象氢卡,而Manager這個(gè)類是一個(gè)“空殼”的類锈至,他本身是沒(méi)有任何的屬性和方法的。他的方法全部都是通過(guò)Python動(dòng)態(tài)添加的方式译秦,從QuerySet類中拷貝過(guò)來(lái)的峡捡。

所以我們?nèi)绻胍獙W(xué)習(xí)ORM模型的查找操作,必須首先要學(xué)會(huì)QuerySet上的一些API的使用筑悴。

返回新的QuerySet的方法
  • filter

  • exclude

  • annotate

  • order_by

  • values

  • values_list

    類似于values们拙。只不過(guò)返回的QuerySet中,存儲(chǔ)的不是字典阁吝,而是元組砚婆。

  • all

  • select_related

    在提取某個(gè)模型的數(shù)據(jù)的同時(shí),也提前將相關(guān)聯(lián)的數(shù)據(jù)提取出來(lái)突勇∽岸ⅲ可以減少數(shù)據(jù)庫(kù)查詢的次數(shù)。selected_related只能用在一對(duì)多或者一對(duì)一中甲馋,不能用在多對(duì)多或者多對(duì)一中埂奈。

    article = Article.objects.get(pk=1)
     >> article.author # 重新執(zhí)行一次查詢語(yǔ)句
     article = Article.objects.select_related("author").get(pk=2)
     >> article.author # 不需要重新執(zhí)行查詢語(yǔ)句了
    
  • prefetch_related

    這個(gè)方法和select_related非常的類似,就是在訪問(wèn)多個(gè)表中的數(shù)據(jù)的時(shí)候定躏,減少查詢的次數(shù)账磺。這個(gè)方法是為了解決多對(duì)一和多對(duì)多的關(guān)系的查詢問(wèn)題。

  • defer

    在一些表中痊远,可能存在很多的字段绑谣,但是一些字段的數(shù)據(jù)量可能是比較龐大的,而此時(shí)你又不需要拗引,因此這時(shí)候我們就可以使用defer來(lái)過(guò)濾掉一些字段借宵。這個(gè)字段跟values有點(diǎn)類似矾削,只不過(guò)defer返回的不是字典壤玫,而是模型。

  • only

    跟defer類似哼凯,只不過(guò)defer是過(guò)濾掉指定的字段欲间,而only是只提取指定的字段。

  • get

  • create

  • get_or_create

    根據(jù)某個(gè)條件進(jìn)行查找断部,如果找到了那么就返回這條數(shù)據(jù)猎贴,如果沒(méi)有查找到,那么就創(chuàng)建一個(gè)。

  • bulk_create

  • count

  • first & last

  • aggregate

  • exists

  • distinct

  • update

  • delete

  • 切片操作

什么時(shí)候Django會(huì)將QuerySet轉(zhuǎn)換為SQL去執(zhí)行
  • 迭代
  • 使用步長(zhǎng)做切片操作
  • 調(diào)用len函數(shù)
  • 調(diào)用list函數(shù)
  • 判斷

9. 多數(shù)據(jù)庫(kù)配置

(暫用不到她渴,知道可以配置多數(shù)據(jù)庫(kù)达址,要用的時(shí)候再學(xué)吧)

10. 執(zhí)行sql語(yǔ)句

Manager.raw(raw_query, params=None, translations=None)

image

帶參數(shù)的SQL

image
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市趁耗,隨后出現(xiàn)的幾起案子沉唠,更是在濱河造成了極大的恐慌,老刑警劉巖苛败,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件满葛,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡罢屈,警方通過(guò)查閱死者的電腦和手機(jī)嘀韧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)缠捌,“玉大人乳蛾,你說(shuō)我怎么就攤上這事”杀遥” “怎么了肃叶?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)十嘿。 經(jīng)常有香客問(wèn)我因惭,道長(zhǎng),這世上最難降的妖魔是什么绩衷? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任蹦魔,我火速辦了婚禮,結(jié)果婚禮上咳燕,老公的妹妹穿的比我還像新娘勿决。我一直安慰自己,他們只是感情好招盲,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布低缩。 她就那樣靜靜地躺著,像睡著了一般曹货。 火紅的嫁衣襯著肌膚如雪咆繁。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,125評(píng)論 1 297
  • 那天顶籽,我揣著相機(jī)與錄音玩般,去河邊找鬼。 笑死礼饱,一個(gè)胖子當(dāng)著我的面吹牛坏为,可吹牛的內(nèi)容都是我干的究驴。 我是一名探鬼主播,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼匀伏,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼洒忧!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起帘撰,我...
    開(kāi)封第一講書(shū)人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤跑慕,失蹤者是張志新(化名)和其女友劉穎万皿,沒(méi)想到半個(gè)月后摧找,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡牢硅,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年蹬耘,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片减余。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡综苔,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出位岔,到底是詐尸還是另有隱情如筛,我是刑警寧澤,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布抒抬,位于F島的核電站杨刨,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏擦剑。R本人自食惡果不足惜妖胀,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望惠勒。 院中可真熱鬧赚抡,春花似錦、人聲如沸纠屋。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)售担。三九已至肉康,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間灼舍,已是汗流浹背吼和。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留骑素,地道東北人炫乓。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓刚夺,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親末捣。 傳聞我的和親對(duì)象是個(gè)殘疾皇子侠姑,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353