1. 程式人生 > 實用技巧 >Django基礎(URL,Template,Models)

Django基礎(URL,Template,Models)

1. Django初步使用

1.1 MVC和MTV框架

1.1.1 MVC

  • M:模型,負責業務物件和資料庫的對映(ORM)
  • V:檢視,負責與使用者的互動(頁面)
  • C:控制器,負責與使用者的互動(頁面)

1.1.2 MTV

  • M:模型(Model),負責業務物件和資料庫的關係對映(ORM)
  • T:模板(Template),負責如何把頁面展示給使用者(html)
  • V:檢視(View),負責業務邏輯,並在適當時候呼叫Model和Template

此外還需一個URL分發器,將一個個URL請求分發給不同的View處理。

1.2. Django的安裝和使用

直接通過pip3 install去下載對應版本的Django即可。

1.2.1 建立django project

先新建一個Django_projects資料夾,進入這個資料夾後,建立第一個專案。

django-admin startproject mysite   # 建立了一個名為"mysite"的Django 專案

django project的目錄結構:

mysite
|--- manage.py        # Django專案裡的工具,可以通過它呼叫django shell和資料庫,啟動關閉專案與專案互動等
|--- mysite              
|--- __init__.py |--- settings.py #
包含了專案的預設設定 |--- urls.py # 負責把URL模式對映到應用程式 |--- wsgi.py

注意:

  • 建立Django專案不能用中文
  • 要將django-admin.exe的路徑配置到環境變數中
    • 這個檔案的位置一般在python直譯器目錄的Scripts目錄下

啟動Django:

python manage.py runserver 127.0.0.1:8080  # 此時已經可以啟動django專案了,只不過什麼邏輯也沒有

1.2.2 建立應用

通過manage.py可以建立應用

python manage.py startapp app01  
# 通過執行manage.py檔案來建立應用,
# 應該在這個manage.py的檔案所在目錄下執行這句話,因為其他目錄裡面沒有這個檔案


python manage.py startapp app02 # 每個應用都有自己的目錄,每個應用的目錄下都有自己的views.py檢視函式和models.py資料庫操作相關的檔案

1.2.3 修改settings配置

將URL中的路徑和本地檔案系統上的路徑做對應關係對映:

STATIC_URL = '/static/'               # 這裡表示的是URL中的路徑
STATICFILES_DIRS=( 
   os.path.join(BASE_DIR,"statics"),  # 這裡表示的是本地檔案系統的路徑
)

將csrf中介軟體選項暫時註釋:

# 'django.middleware.csrf.CsrfViewMiddleware',   #這裡先註釋掉

1.2.4 啟動專案

python manage.py runserver 127.0.0.1:8080  # 本機可以不寫ip地址了 預設是本機的8000埠

2. URL路由系統

2.1 基本使用格式

django2.0之後是使用了path,但是也向下相容使用url,匯入url即可。

from django.conf.urls import url
urlpatterns = [
     url(正則表示式, views檢視函式,引數,別名),
]
# 正則表示式:一個正則表示式字串
# views檢視函式:一個可呼叫物件,通常為一個檢視函式或一個指定檢視函式路徑的字串
# 引數:可選的要傳遞給檢視函式的預設引數(字典形式)
# 別名:一個可選的name引數

2.2 URL分組

2.2.1 無名分組

所謂無名分組,其實就是給檢視函式傳遞位置引數

將要傳遞的引數在放入小括號()中,然後在對應的檢視函式中按順序接收對應的引數即可。

from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [# 無名分組 (給應用檢視函式傳遞位置引數)
    url(r'books/(\d{4})/$', views.year),  # 完全匹配
    url(r'^books/(\d{4})/(\d{2})/$', views.year_mouth),
    url(r'^books/(\d{4})/(\d{2})/(\d{2})/$', views.year_mouth_day),
]
  • urlpatterns中的元素按照書寫順序從上往下逐一匹配正則表示式,一旦匹配成功則不再繼續
  • 若要從URL中捕獲一個值,只需要在它周圍放置一對圓括號(分組匹配)
  • 不需要新增一個前導的反斜槓(也就是寫在正則最前面的那個/),因為每個URL 都有
    • 例如,應該是^books而不是 ^/books
  • 每個正則表示式前面的 'r' 是可選的但是建議加上
  • ^books& 以什麼結尾,以什麼開頭,嚴格限制路徑
  • # 是否開啟URL訪問地址後面沒有/跳轉至帶有/的路徑的配置項,預設是開啟的
    APPEND_SLASH=True

2.2.2 有名分組

所謂有名分組,就是捕獲URL中的值並以關鍵字引數形式傳遞給檢視函式。

分組命名正則表示式組的語法是(?P<name>pattern),其中name是組的名稱,pattern是要匹配的模式。

urlpatterns = [
    url(r'^articles/(?P<year>[0-9]{4})/$', views.year),
# 某年的,(?P<year>[0-9]{4})這是命名引數,那麼函式year(request,year),形參名稱必須是year這個名字
# 如果這個正則後面沒有寫$符號,即便是輸入了月份路徑,也會被它攔截下拉,因為它的正則也能匹配上
url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.month), url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<day>[0-9]{2})/$', views.details), ]
  • 也可以對應views函式的預設值引數,也就是說檢視函式中可以指定引數的預設值
  • 捕獲的引數永遠都是字串

2.3 URL分發

因為一個專案中可能有多個應用,所以我們需要對URL做分發。

要將新建立的應用新增到setttings配置檔案中的INSTALLED_APPS中

使用include即可完成對URL的分發:(include需要手動匯入)

from django.conf.urls import url,include
urlpatterns = [
     # 輸入不同的url找到不同的app 分發給不同的應用的urls.py
    url(r'^app01/', include('app01.urls')), 
     # 這時app01中的urls只需要處理app01後面的那部分url了
    url(r'^app02/', include('app02.urls')),

]

2.4 URL別名

通過給URL定義一個別名來防止URL路徑更改後URL失效。

使用別名:

# 給url匹配模式起名為 home,別名不需要改,路徑就可以隨便改了,別的地方要使用這個路徑,則用這個別名即可
url(r'^home', views.home, name='home'),  
url(r'^index/(\d*)', views.index, name='index'), 

在模板中的引用:

{% url 'home' %}  #模板渲染的時候,被django解析成了這個名字對應的那個url,這個過程叫做反向解析 

3. Views檢視函式

http請求中產生的核心物件:(所在位置:django.http)

  • http請求:HttpRequest物件
  • http響應:HttpResponse物件

3.1 HttpRequest物件

1) path

  • 請求頁面的全路徑,不包括域名,也不包括引數

2) method

  • 請求中使用的HTTP方法的字串表示,全大寫表示
if request.method=="GET":
    do_something()
elif request.method=="POST":
    do_something_else()

3) GET

  • 包含所有HTTP GET引數的類字典物件

4) POST

  • 包含所有HTTP POST引數的類字典物件
  • 伺服器收到空的POST請求的情況有可能發生,也就是說,表單form通過HTTP POST方法提交請求,但是表單中可能沒有資料
    • 因此不能使用if req.POST來判斷是否使用了HTTP POST 方法;應該使用 if req.method=="POST"

5) session

  • 唯一可讀寫的屬性,代表當前會話的字典物件
  • 自己有啟用Django中的session支援時該屬性才可用

6) COOKIES

  • 包含所有cookies的標準Python字典物件
  • keys和values都是字串

7) FILES

  • 包含所有上傳檔案的類字典物件
  • FILES中的每一個Key都是<input type="file" name="" />標籤中 name屬性的值,FILES中的每一個value同時也是一個標準的python字典物件,包含下面三個Keys:
    • filename: 上傳檔名,用字串表示
    • content_type: 上傳檔案的Content Type
    • content: 上傳檔案的原始內容

8) user

  • 是一個django.contrib.auth.models.User物件,代表當前登陸的使用者
  • 如果訪問使用者當前沒有登陸,user將被初始化為django.contrib.auth.models.AnonymousUser的例項
  • 可以通過user的is_authenticated()方法來辨別使用者是否登陸:if req.user.is_authenticated()
  • 只有啟用Django中的AuthenticationMiddleware時該屬性才可用

方法:

  • get_full_path()
    • 得到包含引數的path
  • request.POST.getlist("")

3.2 HttpResponse物件

HttpResponse物件由我們自己建立,且每個view請求處理方法必須返回一個HttpResponse物件。

HttpResponse類在django.http.HttpResponse,需要手動匯入。

HttpResponse物件上擴充套件的常用方法:

  • 頁面渲染:
    • render()
    • render_to_response()
  • 頁面跳轉:
    • redirect("路徑")
  • 直接返回:
    • HttpResponse("xxoo")
  • locals()函式可以直接將函式中所有的變數傳給模板
    • return render(req,"my backend.html",locals())

render和redirect的區別:

  • render的頁面需要模板語言渲染,且url並沒有變化,還是保持不變
  • redirect是直接跳轉,url會改變

4. Template模板系統

模板渲染的兩種特殊符號:

  • 變數相關的用 {{ }}
  • 邏輯相關的用 {% %}

4.1 變數的使用

4.1.1 語法格式

使用雙大括號來引用變數:

{{ var_name }}

Views函式中的程式碼:

def current_time(req):
    now=datetime.datetime.now()
    return render(req, 'current_datetime.html', {'current_date':now}) 
    # 在模板中,就可以使用{{current_date}}來引用這裡的變數

4.1.2 深度變數的查詢

利用點號來查詢深度變數

點號可以訪問列表索引,也可以通過字典的鍵來訪問對應的值,同樣也可以訪問物件的屬性以及方法

{{ items.2 }}      # 通過列表的索引來獲取對應的值
{{ person.name }}  # 通過字典的key來獲取對應的值
{{ date.month }}   # 通過點號來訪問物件的屬性
{{ var.upper }}    # 通過訪問對應的方法來呼叫它

4.1.3 變數的過濾器(filter)

1)語法格式

  • {{ obj|filter:param }}

2)常用的過濾器

# default:如果值是False,就替換成設定的預設值,否則就是用本來的值
{{ value|default:'值是False'}}
# length:返回值的長度,作用於字串和列表 {{ name_list|length }}
# slice:切片,支援python中可用的所有資料型別 {{ name_list|slice:'1:3' }} {{ s|slice:'1::2' }} # add:給變數加上相應的值 {{ value|add:3 }} # capfirst:首字母大寫 {{ value|capfirst }} # upper:字元轉換成大寫 {{ value|upper }} # cut:從字串中移除指定的字元 {{ value|cut:' '}} # date:格式化日期字串 {{ value|date:'Y-m-d' }}    # join:設定連線符將可迭代物件的元素連線在一起,與字串的join方法相同 {{ name_list|join:'_'}} {{ tu|join:'+'}} # safe:告知Django這段程式碼為安全的,不必進行轉義 {{ value|safe}}

4.2 標籤(tag)的使用

4.2.1 使用標籤的格式

  • {% tags %}

4.2.2 常用的標籤

{% if %}

  • {% if %} 標籤接受and,or或者not來測試多個變數值或者否定一個給定的變數
  • {% if %} 標籤不允許同一標籤裡同時出現and和or
  • {% if %} 可以和過濾功能進行配合
{% if num >= 100 and 8 %}
    {% if num > 200 %}
        <p>num大於200</p>
    {% else %}
        <p>num大於100小於200</p>
    {% endif %}
{% elif num < 100%}
    <p>num小於100</p>
{% else %}
    <p>num等於100</p>
{% endif %}

{% for %}

<ul>
{% for obj in list %}
    <li>{{ obj.name }}</li>
{% endfor %}
</ul>

# 在標籤裡可以用reversed來反序迴圈列表
{% for obj in list reversed %}
    ...
{% endfor %}
  • forloop.first 第一次迴圈
  • forloop.last 最後一次迴圈
  • 示例:
    {% for foo in name_list %}
        {% if forloop.first %}
            {{ foo }}
        {% else %}
            <p>只有第一次迴圈列印</p>
        {% endif %}
    {% endfor %}

{% csrf_token %}

  • 用於生成csrf_token的標籤,用於防止跨站攻擊驗證
  • 這裡其實會生成一個隱藏的input標籤,提交時和其他表達標籤一併提交給後臺
  • 使用時在form標籤裡面加上{% csrf_token %}即可
    <form action="{% url "xxoo" %}" >
              <input type="text">
              <input type="submit"value="提交">
              {% csrf_token %}
    </form>

{% url %}

  • 用於引入路由配置的地址
# 給url匹配模式起名為 home,別名不需要改,路徑就可以隨便改了,別的地方要使用這個路徑,則用這個別名即可
url(r'^home', views.home, name='home'),  


# 在模板中的使用
{% url 'home' %}  #模板渲染的時候,被django解析成了這個名字對應的那個url,這個過程叫做反向解析 

{% with %}

  • 用更簡單的變數名替代複雜的變數名
  • 只在with段內有效
    {% with total=fhjsaldfhjsdfhlasdfhljsdal %} {{ total }} {% endwith %}

{% load %}

  • 載入標籤庫

4.3 自定義filter和simple_tag

1)在app中建立templatetags模組(必須建立,且名字不能改)

2)建立 .py檔案,如my_tags.py

from django import template
from django.utils.safestring import mark_safe

register = template.Library()   #register的名字是固定的,不可改變

@register.filter
def filter_multi(v1,v2):
    return  v1 * v2

@register.simple_tag
def simple_tag_multi(v1,v2):
    return  v1 * v2

@register.simple_tag
def my_input(id,arg):
    result = "<input type='text' id='%s' class='%s' />" %(id,arg,)
    return mark_safe(result)

3)在settings中的INSTALLED_APPS配置當前app

  • 要配置當前app,否則Django無法找到自定義的simple_tag
  • 如果找不到,重啟一下Django試試

3)在使用自定義simple_tag和filter的html檔案中匯入之前建立的 my_tags.py :{% load my_tags %}

  • 必須在模板的首行匯入{% load xxx %},這裡是匯入my_tags

4)使用simple_tag和filter

{% load xxx %}           #首行 
    
 # num=12
{{ num|filter_multi:2 }}      # filter_multi只能傳一個值,前面的num將作為它的第一個引數
                              # 而冒號後的值將作為第二個引數

{% simple_tag_multi 2 5 %}    # 引數不限,但不能放在if for語句中
{% simple_tag_multi num 5 %}

# filter_multi可以用在if等語句後,simple_tag不可以
{% if num|filter_multi:30 > 100 %}
    {{ num|filter_multi:30 }}
{% endif %}

4.4 模板的繼承

1)include

  • include標籤允許在(模板中)包含其它的模板的內容。
  • 標籤的引數是所要包含的模板名稱,可以是一個變數,也可以是用單/雙引號硬編碼的字串。
  • 每當在多個模板中出現相同的程式碼時,就應該考慮是否要使用{%include%}來減少重複

2)extends

  • 繼承母版master.html,只需在其他頁面新增一行:
    {% extends 'master.html' %}

3)block

  • 對母版中對應位置的內容進行替換,一般對js,css,html三部分內容定義三個bock
  • 在base模版中設定越多的{% block %}標籤越好
  • 不能在一個模板中定義多個相同名字的block標籤

在母版中定義:

<div class="menu">
    {% block content %}
    {% endblock %}
</div>

在其他頁面對母版繼承後,再進行對應內容的替換:

{% extends master.html %}  # 繼承母版

# 進行對應位置內容的替換
{% block content %}
     base頁面首頁
{% endblock %}

4)保留母版內容並新增新特性

  • 使用super即可

母版html:

<div class="menu">

    {% block content %}
        <div>這是母版測試頁面</div>
    {% endblock %}
</div>

base.html:

{% block content %}
    {{ block.super }}
     base頁面首頁
{% endblock %}

5. Models(ORM單表操作)

ORM是 “物件-關係-對映” 的簡稱。(Object Relational Mapping,簡稱ORM)

5.1 資料庫的配置和使用

1)配置settings檔案

django預設使用sqlite的資料庫,並預設自帶sqlite的資料庫驅動

如果要更改資料庫為MySQL,需要配置如下:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql', 
        'NAME': 'books',  # 資料庫名稱,必須事先建立好
        'USER': 'root',   # 資料庫使用者名稱
        'PASSWORD': '',   # 資料庫密碼
        'HOST': '',       # 資料庫主機,留空預設為localhost
        'PORT': '3306',   # 資料庫埠
    }
}

2)更改MySQL驅動

django預設的MySQL驅動為MySQLdb,而MySQLdb在py3中有問題,所以還需要更改MySQL驅動為pymysql

# 找到專案名檔案下的__init__,在裡面寫入:

import pymysql
pymysql.install_as_MySQLdb()

3)在models中通過類建立資料庫表

在對應app的models檔案中建立資料庫表

  • 每個類就對應一張表
  • 類的每個例項就對應於表中的一條記錄
  • 每個類中的屬性就對應每張表中對應的每個欄位
from django.db import models
# Create your models here.

class UserInfo(models.Model):               # 這裡類就對應於一張表,且必須繼承models.Model
    id = models.AutoField(primary_key=True)  
    name = models.CharField(max_length=16)
    age = models.IntegerField()
    current_date = models.DateField()

    """
    上面的幾個類的屬性通過ORM對映就對應成了:
    create table userinfo(
        id int primary key auto_increment,
        name varchar(16),
        age int,
        current_date date)
    """

4)在資料庫中生成表結構

將上面的類生成真生的資料庫中的表結構

python manage.py makemigrations
# Django 會在相應的 app 的migrations資料夾下面生成 一個python指令碼檔案 

python manage.py migrate
# 生成資料庫表

# 此時,對應app下面的migrations目錄中出現一個0001_initial.py的檔案,這個檔案就是執行了上述指令之後產生的指令碼檔案,這個檔案就是一個記錄

5.2 更多的欄位和引數

5.2.1 欄位

CharField
    # 字串欄位, 用於較短的字串
    # CharField 必須有一個引數 maxlength, 限制該欄位所允許的最大字元數.

IntegerField
    # 用於儲存一個整數

DecimalField
    # 一個浮點數. 必須 提供兩個引數:
    #    max_digits 總位數(不包括小數點和符號)
    #    decimal_places 小數位數
    #        要儲存最大值為 999 (小數點後儲存2位):
    #            models.DecimalField(..., max_digits=5, decimal_places=2)
    #        要儲存最大值一百萬(小數點後儲存10位): 
    #            models.DecimalField(..., max_digits=17, decimal_places=10) 
    #                max_digits大於等於17就能儲存百萬以上的數了
    # admin 用一個文字框(<input type="text">)表示該欄位儲存的資料

AutoField
    # 一個 IntegerField, 新增記錄時它會自動增長,通常不需要直接使用這個欄位
    # 自定義一個主鍵:my_id=models.AutoField(primary_key=True)
    # 如果不指定主鍵,系統會自動新增一個主鍵欄位到 model

BooleanField
    # A true/false field
    # admin 用 checkbox 來表示此類欄位

TextField
    # 一個容量很大的文字欄位
    # admin 用一個 <textarea> (文字區域)表示該欄位資料.(一個多行編輯框)

EmailField
    # 一個帶有檢查Email合法性的 CharField,不接受 maxlength 引數

DateField
    # 一個日期欄位
    # 有下列額外的可選引數:
    #    auto_now    
    #        當物件被儲存時(更新或者新增),自動將該欄位的值設定為當前時間.
    #        通常用於表示 "last-modified" 時間戳.
    #    auto_now_add    
    #        當物件首次被建立時,自動將該欄位的值設定為當前時間.
    #        通常用於表示物件建立時間.
    #    (僅僅在admin中有意義...)

DateTimeField
    # 一個日期時間欄位. 類似 DateField 支援同樣的附加選項

ImageField
    # 類似 FileField, 不過要校驗上傳物件是否是一個合法圖片
    # 它有兩個可選引數:height_field和width_field,如果提供這兩個引數,則圖片將按提供的高度和寬度規格儲存
    
FileField
    # 一個檔案上傳欄位.
    # 要求一個必須有的引數: upload_to, 一個用於儲存上載檔案的本地檔案系統路徑. 
    # 這個路徑必須包含 strftime #formatting,
    # 該格式將被上載檔案的 date/time替換(so that uploaded files don't fill up the given directory).
    # admin 用一個<input type="file">部件表示該欄位儲存的資料(一個檔案上傳部件) .
    #
    # 在一個 model 中使用 FileField 或 ImageField 需要以下步驟:
    #    1) 在 settings 檔案中, 定義一個完整路徑給 MEDIA_ROOT 以便讓 Django在此處儲存上傳檔案
    #            出於效能考慮,這些檔案並不儲存到資料庫
    #            定義MEDIA_URL 作為該目錄的公共 URL. 要確保該目錄對WEB伺服器使用者帳號是可寫的.
    #    2) 在 model 中新增 FileField 或 ImageField, 並確保定義了 upload_to 選項,
    #            以告訴 Django使用 MEDIA_ROOT 的哪個子目錄儲存上傳檔案.
    #            資料庫中要儲存的只是檔案的路徑(相對於 MEDIA_ROOT).
    #        如果 ImageField 叫作 mug_shot, 就可以在模板中以 {{ object.#get_mug_shot_url }} 這樣的方式得到影象的絕對路徑

URLField
    # 用於儲存 URL. 
    # 若 verify_exists 引數為 True (預設), 給定的 URL 會預先檢查是否存在( 即URL是否被有效裝入且沒有返回404響應).
    # admin 用一個 <input type="text"> 文字框表示該欄位儲存的資料(一個單行編輯框)

NullBooleanField
    # 類似 BooleanField, 不過允許 NULL 作為其中一個選項. 
    # 推薦使用這個欄位而不要用 BooleanField 加 null=True 選項
    # admin 用一個選擇框 <select> (三個可選擇的值: "Unknown", "Yes" 和 "No" ) 來表示這種欄位資料

XMLField
    # 一個校驗值是否為合法XML的 TextField
    # 必須提供引數: schema_path, 它是一個用來校驗文字的 RelaxNG schema 的檔案系統路徑.

FilePathField
    # 可選專案為某個特定目錄下的檔名. 
    # 支援三個特殊的引數, 其中第一個是必須提供的.這三個引數可以同時使用.
    #    path    
    #        必需引數. 一個目錄的絕對檔案系統路徑. FilePathField 據此得到可選專案.
    #        Example: "/home/images".
    #    match    
    #        可選引數. 一個正則表示式, 作為一個字串, FilePathField 將使用它過濾檔名. 
    #        注意這個正則表示式只會應用到 base filename 而不是路徑全名. 
    #        Example: "foo.*\.txt^", 將匹配檔案 foo23.txt 卻不匹配 bar.txt 或 foo23.gif.
    #    recursive
    #        可選引數.要麼 True 要麼 False. 預設值是 False. 是否包括 path 下面的全部子目錄.
    #
    # match 僅應用於 base filename, 而不是路徑全名
    #    FilePathField(path="/home/images", match="foo.*", recursive=True)
    #    會匹配 /home/images/foo.gif 而不匹配 /home/images/foo/bar.gif

IPAddressField
    # 一個字串形式的 IP 地址, (i.e. "24.124.1.30").
    
CommaSeparatedIntegerField
    # 用於存放逗號分隔的整數值. 類似 CharField, 必須要有maxlength引數.

5.2.2 引數

null
    # 如果為True,Django 將用NULL 來在資料庫中儲存空值,預設值是 False.
 
blank
    # 如果為True,該欄位允許不填。預設為False。
    # 這與 null 不同。null純粹是資料庫範疇的,而 blank 是資料驗證範疇的。
    # 如果一個欄位的blank=True,表單的驗證將允許該欄位是空值。如果欄位的blank=False,該欄位就是必填的。

default 
    # 欄位的預設值。可以是一個值或者可呼叫物件。如果可呼叫 ,每有新物件被建立它都會被呼叫
    # 如果欄位沒有設定可以為空,將來如果後新增一個欄位,這個欄位就要給一個default值
 
primary_key
    # 如果為True,那麼這個欄位就是模型的主鍵。
    # 如果沒有指定任何一個欄位的primary_key=True,Django會自動新增一個IntegerField欄位做為主鍵
    #     所以除非想覆蓋預設的主鍵行為,否則沒必要設定任何一個欄位的primary_key=True。
 
unique 
    # 如果該值設定為 True, 這個資料欄位的值在整張表中必須是唯一的
 
choices
    # 由二元組組成的一個可迭代物件(例如,列表或元組),用來給欄位提供選擇項
    # 如果設定了choices ,預設的表單將是一個選擇框而不是標準的文字框,
    #    而且這個選擇框的選項就是choices 中的選項
    
db_index
  # 如果db_index=True 則代表著為此欄位設定資料庫索引

DatetimeFieldDateFieldTimeField 這個三個時間欄位,都可以設定如下屬性:
    auto_now_add
    #     配置auto_now_add=True,建立資料記錄的時候會把當前時間新增到資料庫。
    # 
    
    auto_now
    #     配置上auto_now=True,每次更新資料記錄的時候會更新該欄位,標識這條記錄最後一次的修改時間

5.3 增:新增表記錄

1)方式一

在Views的index函式中操作:

def index(request):
    # 例項化一個物件就是一條記錄
    student_obj = models.Student(
        name='hgzero',
        age=18
    )
    
    student_obj.save()   # 將此記錄增加到資料表中
return render(request,'index.html')

2)方式二

通過objects控制器物件來呼叫資料表相應的增刪改查方法。

它可以建立一個新物件儲存到對應的資料表中,並返回這個新建立的物件。

這個models類的物件就稱之為model物件。

new_obj = models.Student.objects.create(
        name='hgzero',
        age=19
    )
print(new_obj)       # Student object
print(new_obj.name)  # hgzero

3)方式三:批量建立

批量插入很多資料:

obj_list = [models.Student(name=f'stu{i}', age=20) for i in range(1, 21)]
models.Student.objects.bulk_create(obj_list)   # 呼叫bulk_create來批量插入資料

5.4 查:獲取行記錄

1)all() 全部取出

  • 通過 objects 控制器呼叫,返回QuerySet型別,裡面有很多個Student類的物件也就是model物件
  • QuerySet類似於列表,可以迴圈遍歷取值
all_objs = models.Student.objects.all()
'''
    < QuerySet[ < Student: Student object >, 
                       < Student: Student object >, 
                       < Student: Student object >,
                        ...'...(remaining elements truncated)...'
              ]>
'''

2)filter(條件) 條件查詢

  • 通過object控制器呼叫,返回QuerySet型別
  • 如果查詢不到內容不會報錯,返回一個空的QuerySet集合
objs = models.Student.objects.filter(id=2)
objs = models.Student.objects.filter(name='xxx', age=18)  # 多條件查詢
print(objs)         # <QuerySet [<Student: hgzero>]>
print(objs[0].id)   # 可以通過索引取值

3)get(條件) 條件查詢

  • 通過object控制器呼叫,返回model物件
  • 通過get條件查詢,查詢的結果有且只有1個
obj = models.Student.objects.get(id=1)  # 返回的是model物件,且查詢結果只能有一個

4)exclude 排除

  • 通過object物件或者QuerySet集合呼叫,返回QuserySet集合
# 排除name為hgzero的行記錄,將剩下所有的返回
objs = models.Student.objects.filter(age=20).exclude(name='hgzero')

5)order_by 排序

  • 通過object物件或者QuerySet集合呼叫,返回QuserySet集合
# object物件呼叫
objs = models.Student.objects.order_by('age')        # 通過姓名升序排列

# queryset集合呼叫
objs = models.Student.objects.all().order_by('age')  # 通過姓名升序排列

6)reverse 反轉

  • 通過order_by返回的QuerySet集合呼叫,返回一個QuerySet集合
# 只能通過order_by返回的QuerySet集合呼叫
objs = models.Student.objects.order_by('id').reverse()  

7)count 計數

  • 通過QuerySet集合呼叫,返回一個元素個數
num = models.Student.objects.all().count()     # 返回的是記錄的條數

num = models.Student.objects.filter(age=20).count()

8)first 返回第一個model物件

  • 通過QuerySet集合呼叫,返回第一個model物件
obj = models.Student.objects.filter(age=20).first()

9)last 返回最後一個model物件

  • 通過QuerySet集合呼叫,返回最後一個model物件
obj = models.Student.objects.filter(age=20).last()

10)exists 判斷是否存在

  • 通過QuerySet集合呼叫,返回bool值
flag = models.Student.objects.filter(age=25).exists()

11)values_list

  • 通過QuerySet集合呼叫,返回一個QuerySet集合
  • 這個QuerySet裡面的元素是元組的形式,而不是model物件
query_tuple = models.Student.objects.filter(age=20).values_list()
# <QuerySet [(4, 'stu1', 20), (24, 'stu2', 20), (27, 'stu3', 20)]>

query_tuple = models.Student.objects.filter(age=20).values_list('name','age')
# 指定想要獲取的欄位

12)values

  • 通過QuerySet集合呼叫,返回一個QuerySet集合
  • 這個QuerySet集合裡面是字典的形式,而不是model物件
query_dict = models.Student.objects.filter(age=19).values()
# <QuerySet [{'id':3, 'name':'stu1', 'age':19}, {'id':25, 'name':'stu2', 'age':19}]>

query_dict = models.Student.objects.filter(age=19).values('name', 'age')
# <QuerySet [{'name':'stu1', 'age':19}, {'name':'stu2', 'age':19}]>

13)distinct 去重

  • 通過QuerySet集合呼叫,返回一個QuerySet集合
  • 對整個物件去重是沒有意義的,因為只要有一個欄位不同,都不是重複的
query_objs = models.Student.objects.filter(age=20).distinct()

query_objs = models.Student.objects.filter(age=20).values('age').distinct()
# 去重一般都用於values或者values_list

14)雙下劃線模糊查詢

query_objs = models.Student.objects.filter(age__gt=19)   # 大於
query_objs = models.Student.objects.filter(age__gte=19)  # 大於等於
query_objs = models.Student.objects.filter(age__lt=20)   # 小於
query_objs = models.Student.objects.filter(age__lte=20)  # 小於等於
query_objs = models.Student.objects.filter(age__range=[18, 20]) # 範圍 左右都包含 query_objs = models.Student.objects.filter(name__contains='xiao') # 針對字串型別,內容含有 query_objs = models.Student.objects.filter(name__icontains='xiao') # 針對字串型別,內容含有 不區分大小寫 query_objs = models.Student.objects.filter(name__startswith='x') # 匹配以x開頭 query_objs = models.Student.objects.filter(name__istartswith='x') # 匹配以x開頭,不區分大小寫 query_objs = models.Student.objects.filter(name__endswith='o') # 匹配以x結尾 query_objs = models.Student.objects.filter(name__iendswith='o') # 匹配以x結尾,不區分大小寫

15)日期

建立日期欄位:

class Birthday(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=16)
    date = models.DateField()

插入日期資料:

 models.Birthday.objects.create(name='stu1', date='2020-06-28')
 models.Birthday.objects.create(name='stu2', date='2020-07-02')

查詢2020年6月出生的人:

query_objs = models.Birthday.objects.filter(date__year='2020',date__month='06')
print(query_objs)  # <QuerySet [<Birthday: stu1>]>

5.5 刪:刪除行記錄

1)呼叫model物件刪除

models.Student.objects.get(id=20).delete()

2)呼叫QuerySet集合刪除

models.Student.objects.filter(age=20).delete()

5.6改:更新行記錄

count = models.Student.objects.filter(name='stu1').update(age=20)

6. Models(ORM多表操作)

6.1 多對多表的建立方式

1)自行建立第三張表

class Book(models.Model):
    title = models.CharField(max_length=32, verbose_name="書名")

class Author(models.Model):
    name = models.CharField(max_length=32, verbose_name="作者姓名")

# 自己建立第三張表,分別通過外來鍵關聯書和作者
class Author2Book(models.Model):
    author = models.ForeignKey(to="Author")
    book = models.ForeignKey(to="Book")

2)通過ManyToManyField自動建立

class Book(models.Model):
    title = models.CharField(max_length=32, verbose_name="書名")

# 通過ORM自帶的ManyToManyField自動建立第三張表
class Author(models.Model):
    name = models.CharField(max_length=32, verbose_name="作者姓名")
    books = models.ManyToManyField(to="Book", related_name="authors")  
#自動生成的第三張表我們是沒有辦法新增其他欄位的