Django框架簡介

miner_k發表於2018-01-07

框架(framework),指為解決一個開放性的問題而設計的具有一 定約束性的支撐結構,使用框架可以幫助你快速開發特定的系統。

常見的python web框架
`Full-Stack Framework`(全棧框架)
Django、web2py、TurboGears、Pylons、......

`Non Full-Stack Framework`(非全棧框架)
tornado、Flask、Bottle、webpy、pyramid.....

部署Django環境

python 3.5.2
Django==1.11.5
PyMySQL==0.7.11
pytz==2017.2

下載安裝Django模組

  • 方法一:使用pip工具

    更新pip的版本

    python -m pip install --upgrade pip

    首先要確保安裝了pip工具

     pip install Django
  • 方法二:使用git

    $ git clone git://github.com/django/django.git
    $ pip install -e django/
    
  • 方法三:下載Django的py包,然後使用python命令安裝

  • 檢測是否安裝成功

    In [1]: import django
    
    In [2]: django.VERSION
    Out[2]: (1, 11, 4, u'final', 0)
    

安裝資料庫

django預設提供了Sqlite資料庫

安裝python和mysql的連線模組。

pip  install PyMySQL     連線資料庫

啟動Apache

Django-admin命令

>django-admin.py help

Type 'django-admin.py help <subcomm

Available subcommands:

[django]
    check         檢查Django專案的完整性
    compilemessages  編輯語言檔案
    createcachetable  
    dbshell       進入Django dbshell
    diffsettings  檢視你的配置和Django的預設配置有和不同
    dumpdata      匯出資料
    flush         清空資料庫
    inspectdb
    loaddata       匯入資料
    makemessages   建立語言檔案
    makemigrations 生成資料庫同步指令碼
    migrate        同步資料庫
    runserver      執行開發伺服器
    sendtestemail
    shell          進入django shell
    showmigrations  檢視生成資料庫的同步指令碼
    sqlflush       檢視生成清空資料庫的指令碼
    sqlmigrate     檢視資料庫同步的sql語句
    sqlsequencereset
    squashmigrations
    startapp       建立一個app
    startproject    建立一個專案
    test
    testserver

檢視指定命令的幫助文件

>django-admin.py help startproject

usage: django-admin.py startproject [-h] [--version] [-v {0,1,2,3}]
                                    [--settings SETTINGS]
                                    [--pythonpath PYTHONPATH] [--traceback]
                                    [--no-color] [--template TEMPLATE]
                                    [--extension EXTENSIONS] [--name FILES]
                                    name [directory]

Creates a Django project directory structure for the given project name in th
current directory or optionally in the given directory.

positional arguments:
  name                  Name of the application or project.
  directory             Optional destination directory

optional arguments:
  -h, --help            show this help message and exit

建立Django第一個app(helloworld)

[root@miner-k ~]# mkdir /app
[root@miner-k ~]# cd /app/
[root@miner-k app]# django-admin  startproject mysite

[root@miner-k app]# tree .
.
└── mysite                 #Django專案的名稱,剛才建立的專案名稱
    ├── manage.py          #命令列實用程式,與Django進行互動。
    └── mysite
        ├── __init__.py
        ├── settings.py      #配置檔案
        ├── urls.py          #url的設定
        └── wsgi.py          #動態閘道器介面檔案

Django-admin.py是Django的一個用於管理任務的命令工具,manage.py是對Django-admin.py的簡單包裝,每一個Django project裡面都會包含一個manage.py

[root@miner-k mysite]# python manage.py help

Type 'manage.py help <subcommand>' for help on a specific subcommand.

Available subcommands:

[auth]
    changepassword
    createsuperuser

[contenttypes]
    remove_stale_contenttypes

[django]
    check
    compilemessages
    createcachetable
    dbshell
    diffsettings

建立一個名為hello的app

[root@miner-k mysite]# python manage.py startapp hello

一般不同的APP負責不同的功能,一個app負責一個功能。

[root@miner-k mysite]# tree hello/
blog/
├── admin.py            #管理後臺的配置
├── apps.py         #app的配置
├── __init__.py
├── migrations          #資料庫的管理
│   └── __init__.py
├── models.py           #模型程式碼的配置
├── tests.py            #單元測試
└── views.py            #業務程式碼

登入到Django的後臺

  1. 生成同步資料庫的指令碼

    D:\pythonwork\django\mysite>python manage.py makemigrations
    No changes detected
    
  2. 同步資料

    D:\pythonwork\django\mysite>python manage.py migrate
    Operations to perform:
      Apply all migrations: admin, auth, contenttypes, sessions
    Running migrations:
      Applying contenttypes.0001_initial... OK
      Applying auth.0001_initial... OK
      Applying admin.0001_initial... OK
      auth.0007_alter_validators_add_error_messages... OK
      Applying auth.0008_alter_user_username_max_length... OK
      Applying sessions.0001_initial... OK
  3. 建立超級使用者以及密碼(密碼不能太短)

    D:\pythonwork\django\mysite>python35 manage.py createsuperuser
    Username (leave blank to use 'administrator'): admin
    Email address:
    Password:
    Password (again):
    Superuser created successfully.
  4. 修改超級使用者的密碼

    D:\pythonwork\django\mysite>python35 manage.py changepassword admin
    Changing password for user 'admin'
    Password:
    
  5. 啟動服務

    D:\pythonwork\django\mysite>python35 manage.py runserver
    
    Performing system checks...
    
    System check identified no issues (0 silenced).
    October 10, 2017 - 20:52:07
    Django version 1.11.5, using settings 'mysite.settings'
    Starting development server at http://127.0.0.1:8000/
    Quit the server with CTRL-BREAK.
  6. 登入後臺
    登入後臺的URL:http://127.0.0.1:8000/admin/

設定服務監控的埠

啟動的時候指定監聽的埠

D:\pythonwork\django\mysite>python35 manage.py runserver 8080
Performing system checks...

System check identified no issues (0 silenced).
September 12, 2017 - 22:13:32
Django version 1.11.5, using settings 'mysite.settings'
Starting development server at http://127.0.0.1:8080/
Quit the server with CTRL-BREAK.

建立一個網頁

靜態檔案存放到app的目錄下

預設情況下
static 目錄:存放css、js、圖片等靜態檔案
templates 目錄:存放模板

這裡寫圖片描述

在app中配置

  1. 修改hello的app目錄下的views.py定義一個業務請求處理的函式

    from django.shortcuts import render
    
    
    # Create your views here.
    
    def hello(request):
        return  render(request,'table.html ')
  2. 定義一個模板並引用靜態檔案

    在app的目錄下建立兩個目錄statictemplates
    將static目錄下存放CSS、js格式的檔案
    在template目錄下存放table.html檔案

在專案mysite目錄中配置

  1. 在settings.py裡面的INSTALLED_APPS中加入hello,將新建的app增加到專案中。

    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'hello',
    ]
    
  2. 在urls.py裡面定義url地址

    
    from django.conf.urls import url
    from django.contrib import admin
    from hello import views          #從指定的app中匯入views
    '''url(URL路徑正規表示式,app中views的函式,別名)'''   
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^hello/', views.hello,name='hello'),
    ]

啟動服務

訪問測試
訪問網站:http://127.0.0.1:8000/hello/

靜態檔案、模板存放到工程目錄下

這裡寫圖片描述

修改seting.py檔案

'''在DIRS中指定模板的目錄'''

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': ['templates'],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]


'''指定靜態檔案的目錄'''
STATICFILES_DIRS = (os.path.join(BASE_DIR, 'static'),)

在app中設定URL

上面的URL的配置是在工程的urls.py中設定訪問的URL,現在為了方便管理不同的URL,需要在不同的app下設定URL

工程中的urls.py配置

''' 包含app中URL的配置檔案
    1.匯入incloude():
        from django.conf.urls import url, include
    2. 增加URL的引數:  
        url(r'^blog/', include('blog.urls'))
        r'^blog/' :訪問的字尾
        include('blog.urls'):指定包含的URL的存放位置。blog目錄下的urls
'''
from django.conf.urls import url,include
from django.contrib import admin


urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^', include('hello.urls')),
]

app中的urls.py的配置

from django.conf.urls import url
from hello import views


urlpatterns = [
       url(r'^hello/$', views.hello),
]

注意:訪問URL時,URL是專案中URL中配置加app中的URL。如果在工程中的URl中設定url(r'^abc/', include('hello.urls')),在app中設定url(r'^hello/$', views.hello),訪問時輸入的URl為http://127.0.0.1:8000/abc/hello/

MTV和MVC

在鑽研更多程式碼之前,讓我們先花點時間考慮下 Django 資料驅動 Web 應用的總體設計。

Django 的設計鼓勵鬆耦合及對應用程式中不同部分的嚴格分割。 遵循這個理念的話,要想修改應用的某部分而不影響其它部分就比較容易了。 在檢視函式中,我們已經討論了通過模板系統把業務邏輯和表現邏輯分隔開的重要性。 在資料庫層中,我們對資料訪問邏輯也應用了同樣的理念。

這裡寫圖片描述

把資料存取邏輯、業務邏輯和表現邏輯組合在一起的概念有時被稱為軟體架構的 Model-View-Controller (MVC)模式。 在這個模式中, Model 代表資料存取層,View 代表的是系統中選擇顯示什麼和怎麼顯示的部分,Controller 指的是系統中根據使用者輸入並視需要訪問模型,以決定使用哪個檢視的那部分。

Django 緊緊地遵循這種 MVC 模式,可以稱得上是一種 MVC 框架。 以下是 Django 中 M、V 和 C 各自的含義:

  • M ,資料存取部分,由django資料庫層處理。
  • V ,選擇顯示哪些資料要顯示以及怎樣顯示的部分,由檢視和模板處理。
  • C ,根據使用者輸入委派檢視的部分,由 Django 框架根據 URLconf 設定,對給定 URL 呼叫適當的 Python 函式。

由於 C 由框架自行處理,而 Django 裡更關注的是模型(Model)、模板(Template)和檢視(Views),Django 也被稱為 MTV 框架 。在MTV 開發模式中:

  • M 代表模型(Model),即資料存取層。 該層處理與資料相關的所有事務: 如何存取、如何驗證有效性、包含哪些行為以及資料之間的關係等。
  • T 代表模板(Template),即表現層。 該層處理與表現相關的決定: 如何在頁面或其他型別文件中進行顯示。
  • V 代表檢視(View),即業務邏輯層。 該層包含存取模型及調取恰當模板的相關邏輯。 你可以把它看作模型與模板之間的橋樑。

如果你熟悉其它的 MVC Web開發框架,比方說 Ruby on Rails,你可能會認為 Django 檢視是控制器,而 Django 模板是檢視。 很不幸,這是對 MVC 不同詮釋所引起的錯誤認識。 在 Django 對 MVC 的詮釋中,檢視用來描述要展現給使用者的資料;不是資料 如何展現 ,而且展現 哪些 資料。 相比之下,Ruby on Rails 及一些同類框架提倡控制器負責決定向使用者展現哪些資料,而檢視則僅決定 如何 展現資料,而不是展現 哪些 資料。

這裡寫圖片描述

MTV的響應模式如下所示:

  1. Web伺服器(中介軟體)收到一個http請求
  2. Django在URLconf裡查詢對應的檢視(View)函式來處理http請求
  3. 檢視函式呼叫相應的資料模型來存取資料、呼叫相應的模板向使用者展示頁面
  4. 檢視函式處理結束後返回一個http的響應給Web伺服器
  5. Web伺服器將響應傳送給客戶端

Django中的配置檔案的簡介

url.py詳解

Django 決定要使用的根URLconf 模組。通常,這個值就是ROOT_URLCONF 的設定,但是如果進來的HttpRequest 物件具有一個urlconf 屬性(通過中介軟體request processing 設定),則使用這個值來替換ROOT_URLCONF 設定。

url.py:URL分發器(路由配置檔案)
URL配置(URLconf)就像配置Django所支援的網站目錄,他的本質是URL模式以及要為該URL模式呼叫的檢視函式之間的對映表。

URL模式:

urlpatterns = [
       url(正規表示式,view函式,引數,別名,字首),
]

#url的函式定義
url(regex, view, kwargs=None, name=None):
例項:正規表示式的匹配

下面是一個簡單的 URLconf:

from django.conf.urls import url

from . import views

urlpatterns = [
    url(r'^articles/2003/$', views.special_case_2003),
    url(r'^articles/([0-9]{4})/$', views.year_archive),
    url(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive),
    url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail),
]

注:

  • 若要從URL 中捕獲一個值,只需要在它周圍放置一對圓括號。
  • 不需要新增一個前導的反斜槓,因為每個URL 都有。例如,應該是^articles 而不是 ^/articles。
  • 每個正規表示式前面的’r’ 是可選的但是建議加上。它告訴Python 這個字串是“原始的” —— 字串中任何字元都不應該轉義。

一些請求的例子:

  1. /articles/2005/03/ 請求將匹配列表中的第三個模式。Django
    將呼叫函式views.month_archive(request, ‘2005’, ‘03’)。
  2. /articles/2005/3/ 不匹配任何URL 模式,因為列表中的第三個模式要求月份應該是兩個數字。
  3. /articles/2003/
    將匹配列表中的第一個模式不是第二個,因為模式按順序匹配,第一個會首先測試是否匹配。請像這樣自由插入一些特殊的情況來探測匹配的次序。
  4. /articles/2003 不匹配任何一個模式,因為每個模式要求URL 以一個斜線結尾。
  5. /articles/2003/03/03/ 將匹配最後一個模式。Django 將呼叫函式views.article_detail(request, ‘2003’, ‘03’, ‘03’)。
正則表達中傳遞引數(命名組)

上面的示例使用簡單的、沒有命名的正規表示式組(通過圓括號)來捕獲URL 中的值並以位置 引數傳遞給檢視。在更高階的用法中,可以使用命名的正規表示式組來捕獲URL 中的值並以關鍵字 引數傳遞給檢視。

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

下面是以上URLconf 使用命名組的重寫:


from django.conf.urls import url

from . import views

urlpatterns = [
    url(r'^articles/2003/$', views.special_case_2003),
    url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),
    url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.month_archive),
    url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<day>[0-9]{2})/$', views.article_detail),
]

這個實現與前面的示例完全相同,只有一個細微的差別:捕獲的值作為關鍵字引數而不是位置引數傳遞給檢視函式。例如:

  1. /articles/2005/03/ 請求將呼叫views.month_archive(request, year=’2005’, month=’03’)函式,而不是views.month_archive(request, ‘2005’, ‘03’)。
  2. /articles/2003/03/03/ 請求將呼叫函式views.article_detail(request, year=’2003’, month=’03’, day=’03’)。

在實際應用中,這意味你的URLconf 會更加明晰且不容易產生引數順序問題的錯誤 —— 你可以在你的檢視函式定義中重新安排引數的順序。當然,這些好處是以簡潔為代價;conf

命名組和傳遞引數的區別:
該方法傳遞的引數是變數,可以根據客戶端等的不同而變化,但是使用ru()中傳遞的引數是固定值。

例項:傳遞引數

urls.py

from django.conf.urls import url
from hello import views

'''向views中的hello函式中傳遞引數a'''
urlpatterns = [
       url(r'^hello/$', views.hello,{'a':123}),
]

views.py

from django.shortcuts import render
from django.contrib.auth.models import User
# Create your views here.


'''函式hello接收引數a,否則會報錯'''
def hello(request,a):
    user_list = User.objects.all()
    print(a)
    return  render(request,"table.html ",{'user_list':user_list})

URL的分解器,include函式

通常一個URL分解器對應一個URL匹配模組,它可以包含多個URL模式,也可以包含多個其他的URL分解器。通常這種包含關係結構設計,實現了Django對URL的層級解析。

工程中的urls.py配置

''' 包含app中URL的配置檔案
    1.匯入incloude():
        from django.conf.urls import url, include
    2. 增加URL的引數:  
        url(r'^blog/', include('blog.urls'))
        r'^blog/' :訪問的字尾
        include('blog.urls'):指定包含的URL的存放位置。blog目錄下的urls模組
'''
from django.conf.urls import url,include
from django.contrib import admin


urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^', include('hello.urls')),
]

app中的urls.py的配置

from django.conf.urls import url
from hello import views


urlpatterns = [
       url(r'^hello/$', views.hello),
]

注意:訪問URL時,URL是專案中URL中配置加app中的URL。如果在工程中的URl中設定url(r'^abc/', include('hello.urls')),在app中設定url(r'^hello/$', views.hello),訪問時輸入的URl為http://127.0.0.1:8000/abc/hello/

總結

urls.py中,需要配置訪問時的URL

  1. 設定urls.py的主目錄

    '''在工程目錄中的seting.py中設定,設定工程mysite下的urls為主URL的配置檔案'''
    ROOT_URLCONF = 'mysite.urls'
  2. 配置方法:

    '''配置URL的正規表示式以及對應的URL對應的操作(函式)'''
    from django.conf.urls import url
    urlpatterns = [
           url('正規表示式', '操作函式''引數','別名','字首'),
    ]
    
  3. 為方便管理URL設定層目錄include函式

    ''' 包含app中URL的配置檔案
    1.匯入incloude():
        from django.conf.urls import url, include
    2. 增加URL的引數:  
        url(r'^blog/', include('blog.urls'))
        r'^blog/' :訪問的字尾
        include('blog.urls'):指定包含的URL的存放位置。blog目錄下的urls模組
    '''
    from django.conf.urls import url,include
    from django.contrib import admin
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^', include('hello.urls')),
    ]

view.py簡介

Django 使用Request 物件和Response 物件在系統間傳遞狀態。

當請求一個頁面時,Django會建立一個包含請求後設資料的 HttpRequest 物件。 當Django 載入對應的檢視時,HttpRequest 物件將作為檢視函式的第一個引數。每個檢視會返回一個HttpResponse 物件。

from django.shortcuts import render
from django.contrib.auth.models import User

from django.http import HttpRequest,HttpResponse

def hello(request,a):
    user_list = User.objects.all()
    print(a)
    return  render(request,"table.html ",{'user_list':user_list})

HttpRequest物件

在函式最開始的第一個引數,request是HttpRequest的例項。

屬性
  • HttpRequest.scheme

    一個字串,表示請求的方案(通常是http 或https)

  • HttpRequest.body

    一個位元組字串,表示原始HTTP 請求的正文。它對於處理非HTML 形式的資料非常有用:二進位制影像、XML等。 如果要處理常規的表單資料,應該使用HttpRequest.POST。

  • HttpRequest.path

    一個字串,表示請求的頁面的完整路徑,不包含域名。例如:”/music/bands/the_beatles/”

  • HttpRequest.method

    一個字串,表示請求使用的HTTP 方法。必須使用大寫

    if request.method == 'GET':
        do_something()
    elif request.method == 'POST':
        do_something_else()
  • HttpRequest.GET

    一個類似於字典的物件,包含HTTP GET 的所有引數

  • HttpRequest.POST

    一個包含所有給定的HTTP POST引數的類字典物件,提供了包含表單資料的請求。詳情請參考下面的QueryDict 文件。如果需要訪問請求中的原始或非表單資料,可以使用HttpRequest.body 屬性。

    POST 請求可以帶有空的POST 字典 —— 如果通過HTTP POST 方法請求一個表單但是沒有包含表單資料的話。因此,不應該使用if request.POST 來檢查使用的是否是POST 方法;應該使用if request.method == “POST”(參見上文)。|

    注意:POST 不包含上傳的檔案資訊

  • HttpRequest.COOKIES

    一個標準的Python 字典,包含所有的cookie。鍵和值都為字串

  • HttpRequest.FILES

    一個類似於字典的物件,包含所有的上傳檔案。FILES 中的每個鍵為 中的name。

    注意,FILES 只有在請求的方法為POST 且提交的 帶有enctype=”multipart/form-data” 的情況下才會包含資料。否則,FILES 將為一個空的類似於字典的物件

  • HttpRequest.META

    一個標準的Python 字典,包含所有的HTTP 頭部。具體的頭部資訊取決於客戶端和伺服器,下面是一些示例:

    CONTENT_LENGTH —— 請求的正文的長度(是一個字串)。
    CONTENT_TYPE —— 請求的正文的MIME 型別。
    HTTP_ACCEPT —— 響應可接收的Content-Type。
    HTTP_ACCEPT_ENCODING —— 響應可接收的編碼。
    HTTP_ACCEPT_LANGUAGE —— 響應可接收的語言。
    HTTP_HOST —— 客服端傳送的HTTP Host 頭部。
    HTTP_REFERER —— Referring 頁面。
    HTTP_USER_AGENT —— 客戶端的user-agent 字串。
    QUERY_STRING —— 單個字串形式的查詢字串(未解析過的形式)。
    REMOTE_ADDR —— 客戶端的IP 地址。
    REMOTE_HOST —— 客戶端的主機名。
    REMOTE_USER —— 伺服器認證後的使用者。
    REQUEST_METHOD —— 一個字串,例如”GET” 或”POST”。
    SERVER_NAME —— 伺服器的主機名。
    SERVER_PORT —— 伺服器的埠(是一個字串)。
    從上面可以看到,除CONTENT_LENGTH 和CONTENT_TYPE 之外,請求中的任何HTTP 頭部轉換為META 的鍵時,都會將所有字母大寫並將連線符替換為下劃線最後加上HTTP_ 字首。所以,一個叫做X-Bender 的頭部將轉換成META 中的HTTP_X_BENDER 鍵。

  • HttpRequest.user

    一個AUTH_USER_MODEL 型別的物件,表示當前登入的使用者。如果使用者當前沒有登入,user 將設定為django.contrib.auth.models.AnonymousUser 的一個例項。你可以通過is_authenticated() 區分它們,像這樣:

    if request.user.is_authenticated():
        # Do something for logged-in users.
    else:
        # Do something for anonymous users.

    user 只有當Django 啟用AuthenticationMiddleware 中介軟體時才可用。更多資訊,參見Django 中的使用者認證。

  • HttpRequest.session

    一個既可讀又可寫的類似於字典的物件,表示當前的會話。只有當Django 啟用會話的支援時才可用

Response物件

每一個view請求處理方法必須有一個HttpResponse物件的

傳遞字串

典型的應用是傳遞一個字串作為頁面的內容到HttpResponse 建構函式:

>>> from django.http import HttpResponse
>>> response = HttpResponse("Here's the text of the Web page.")
>>> response = HttpResponse("Text only, please.", content_type="text/plain")

如果你想增量增加內容,你可以將response 看做一個類檔案物件

>>> response = HttpResponse()
>>> response.write("<p>Here's the text of the Web page.</p>")
>>> response.write("<p>Here's another paragraph.</p>")
Django的快捷函式
render

格式:

render(request, template_name[, context][, context_instance][, content_type][, status][, current_app][, dirs][, using])[source]
結合一個給定的模板和一個給定的上下文字典,並返回一個渲染後的 HttpResponse 物件

必選引數:
request:該request用於生成response
template_name:要使用的模板的完整名稱或者模板名稱的一個序列。

可選引數:
content_type:生成的文件要使用的MIME 型別。預設為DEFAULT_CONTENT_TYPE 設定的值
status:響應的狀態碼。預設為200

下面的示例渲染模板myapp/index.html,MIME 型別為application/xhtml+xml:

from django.shortcuts import render

def my_view(request):
    # View code here...
    return render(request, 'myapp/index.html', {"foo": "bar"},
        content_type="application/xhtml+xml")

這個示例等同於:

from django.http import HttpResponse
from django.template import RequestContext, loader

def my_view(request):
    # View code here...
    t = loader.get_template('myapp/index.html')
    c = RequestContext(request, {'foo': 'bar'})
    return HttpResponse(t.render(c),
        content_type="application/xhtml+xml")
render_to_response

格式:

render_to_response(template_name[, context][, context_instance][, content_type][, status][, dirs][, using])[source]

根據一個給定的上下文字典渲染一個給定的目標,並返回渲染後的HttpResponse

必選引數:
template_name:要使用的模板的完整名稱或者模板名稱的一個序列。如果給出的是一個序列,將使用存在的第一個模板。

可選引數:
content_type:生成的文件要使用的MIME 型別。預設為DEFAULT_CONTENT_TYPE 設定的值
status:響應的狀態碼。預設為200

例項:

下面的示例渲染模板myapp/index.html,MIIME 型別為application/xhtml+xml:

from django.shortcuts import render_to_response

def my_view(request):
    # View code here...
    return render_to_response('myapp/index.html', {"foo": "bar"},
        content_type="application/xhtml+xml")

這個示例等同於:

from django.http import HttpResponse
from django.template import Context, loader

def my_view(request):
    # View code here...
    t = loader.get_template('myapp/index.html')
    c = Context({'foo': 'bar'})
    return HttpResponse(t.render(c),
        content_type="application/xhtml+xml")
重定向
redirect(to, [permanent=False, ]*args, **kwargs)[source]

為傳遞進來的引數返回HttpResponseRedirect 給正確的URL 。

引數可以是:

  • 一個模型:將呼叫模型的get_absolute_url() 函式
  • 一個檢視,可以帶有引數:將使用urlresolvers.reverse 來反向解析名稱
  • 一個絕對的或相對的URL,將原封不動的作為重定向的位置。

預設返回一個臨時的重定向;傳遞permanent=True 可以返回一個永久的重定向

示例:

  1. 通過傳遞一個物件;將呼叫get_absolute_url() 方法來獲取重定向的URL:

    from django.shortcuts import redirect
    
    def my_view(request):
        ...
        object = MyModel.objects.get(...)
        return redirect(object)
  2. 通過傳遞一個檢視的名稱,可以帶有位置引數和關鍵字引數;將使用reverse() 方法反向解析URL:

    def my_view(request):
        ...
        return redirect('some-view-name', foo='bar')
  3. 傳遞要重定向的一個硬編碼的URL:

    def my_view(request):
        ...
        return redirect('/some/url/')

    也可以是一個完整的URL:

    def my_view(request):
        ...
        return redirect('http://example.com/')

    預設情況下,redirect() 返回一個臨時重定向。以上所有的形式都接收一個permanent 引數;如果設定為True,將返回一個永久的重定向:

    def my_view(request):
        ...
        object = MyModel.objects.get(...)
        return redirect(object, permanent=True) 
    
HttpResponse子類

Django包含了一系列的HttpResponse衍生類(子類),用來處理不同型別的HTTP 響應(response)。與 HttpResponse相同, 這些衍生類(子類)存在於django.http之中。

  • class HttpResponseRedirect

    建構函式的第一個引數是必要的 — 用來重定向的地址。這些能夠是完全特定的URL地址(比如,’http://www.yahoo.com/search/‘),或者是一個不包含域名的絕對路徑地址(例如, ‘/search/’)。關於建構函式的其他引數,可以參見 HttpResponse。注意!這個響應會返回一個302的HTTP狀態碼。

    url
    這個只讀屬性,代表響應將會重定向的URL地址(相當於Location response hader)。

  • class HttpResponsePermanentRedirect
    與HttpResponseRedirect一樣,但是它會返回一個永久的重定向(HTTP狀態碼301)而不是一個“found”重定向(狀態碼302)。

  • class HttpResponseNotModified
    建構函式不會有任何的引數,並且不應該向這個響應(response)中加入內容(content)。使用此選項可指定自使用者上次請求(狀態程式碼304)以來尚未修改頁面。

  • class HttpResponseBadRequest
    與HttpResponse的行為類似,但是使用了一個400的狀態碼。

  • class HttpResponseNotFound
    與HttpResponse的行為類似,但是使用的404狀態碼。

  • class HttpResponseForbidden
    與HttpResponse類似,但使用403狀態程式碼。

資料庫

在專案的目錄下setings.py中

#setings.py
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}

mysql:
引擎的名稱:django.db.backends.mysql

mysql的驅動程式:

  • MySQLdb是一個由Andy Dustman開發,已經發展並支援十多年的一個本地驅動。
  • mysqlclient是MySQLdb的一個分支,它與python3有著特別好的契合並且可以作為MySQLdb的直接替代。在書寫這篇的時候,這是在Django使用MySQL的推薦的選擇。
  • MySQL Connector/Python是一個來自Oracle的純python驅動,它不需要MySQL client庫或在標準庫之外的任何Python模組。
  • PyMySQL(純python的mysql驅動):

連線資料庫

  • 安裝PyMySQL
  • 修改配置檔案
  • 在工程目錄中init.py中寫入:

    import pymysql
    pymysql.install_as_MySQLdb()

連線設定將被用在這些命令上:

  • OPTIONS
  • NAME,USER,PASSWORD,HOST,PORT
  • MySQL選項檔案。

換句話說,如果你設定資料庫的名稱在OPTIONS, 這將優先於NAME, 這將覆蓋任何在MySQL option file中的東西.

下面是使用一個MySQL選擇檔案一個示例配置:

# settings.py
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'OPTIONS': {
            'read_default_file': '/path/to/my.cnf',
        },
    }
}


# my.cnf
[client]
database = NAME
user = USER
password = PASSWORD
default-character-set = utf8

其他幾個MySQLdb連線選項可能是有用的,例如ssl, init_command, and sql_mode. 查閱 MySQLdb documentation瞭解更多細節。

初始化資料庫

> python manage.py migrate

ORM機制簡介

ORM是什麼?:(在django中,根據程式碼中的類自動生成資料庫的表也叫–code first)

ORM:Object Relational Mapping(物件關係對映)

類名對應——》資料庫中的表名

類屬性對應———》資料庫裡的欄位

類例項對應———》資料庫表裡的一行資料

obj.id obj.name…..類例項物件的屬性

呼叫sql語句

# views.py

from django.shortcuts import render
from django.contrib.auth.models import User

from django.http import HttpRequest,HttpResponse

# Create your views here.
def hello(request,a):
    user_list = User.objects.all()
    print(user_list.query)
    return  render(request,"table.html ",{'user_list':user_list})

直接在螢幕上顯示執行的sql語句

# 在project的setings.py

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

常用操作

'''準備環境'''
D:\pythonwork\django\mysite>python manage.py shell
>>> from hello.models import *
插入資料

create和save方法

objects:model預設管理器,create是管理器的方法,save是model物件的方法。
插入主外來鍵關係的時候,可以用物件的方式,也可以直接關聯ID的方式
插入多對多關係的時候要分步操作。

插入一個作者:

'''建立一個作者'''
>>> Author.objects.create(name='tom')
(0.000) SELECT @@SQL_AUTO_IS_NULL; args=None
(0.052) INSERT INTO `hello_author` (`name`) VALUES ('tom'); args=['tom']
<Author: Author object>
>>>

插入一個作者的詳細記錄:

>>> AuthorDetail.objects.create(sex=0,email='123456@qq.com',address='北京市海淀區梧桐路25號',birthday='19920202',author_id=1)

插入一個出版社的記錄

>>> pub = Publisher()
>>> pub.name = "中國電子出版社"
>>> pub.address = "北京市"
>>> pub.city = "北京市"
>>> pub.state_province = '北京市'
>>> pub.country = '中國'
>>> pub.website = 'http://www.miner-k.com'
>>> pub.save()
(0.052) INSERT INTO `hello_publisher` (`name`, `address`, `city`, `state_provinc
e`, `country`, `website`) VALUES ('中國電子出版社', '北京市', '北京市', '北京市'
, '中國', 'http://www.miner-k.com'); args=['中國電子出版社', '北京市', '北京市',
 '北京市', '中國', 'http://www.miner-k.com']

插入一本書的記錄

>>> Book.objects.create(title='python入門到精通',publisher=pub,publisher_date='2012-12-12')
(0.067) INSERT INTO `hello_book` (`title`, `publisher_id`, `publisher_date`) VALUES ('python入門到精通', 1, '2012-12-12'); args=['python入門到精通', 1, '2012-12-12']
<Book: Book object>

插入書、作者、出版商關係的記錄

>>> book = Book.objects.get(id=1)
(0.002) SELECT VERSION(); args=None
(0.002) SELECT `hello_book`.`id`, `hello_book`.`title`, `hello_book`.`publisher_id`, `hello_book`.`publisher_date` FROM `hello_book` WHERE `hello_book`.`id` = 1; args=(1,)

>>> author = Author.objects.get(id=1)
(0.002) SELECT `hello_author`.`id`, `hello_author`.`name` FROM `hello_author` WHERE `hello_author`.`id` = 1; args=(1,)

>>> book.authors.add(author)
(0.004) SELECT `hello_book_authors`.`author_id` FROM `hello_book_authors` WHERE
(`hello_book_authors`.`book_id` = 1 AND `hello_book_authors`.`author_id` IN (1)); args=(1, 1)
(0.066) INSERT INTO `hello_book_authors` (`book_id`, `author_id`) VALUES (1, 1); args=(1, 1)
>>>
修改資料

update和save方法
updete是QuerySet物件的方法

>>> author = Author.objects.get(id=1)
(0.002) SELECT `hello_author`.`id`, `hello_author`.`name` FROM `hello_author` WHERE `hello_author`.`id` = 1; args=(1,)
>>> author.name = 'jim'
>>> author.save()
(0.586) UPDATE `hello_author` SET `name` = 'jim' WHERE `hello_author`.`id` = 1;args=('jim', 1)
查詢資料(惰性查詢)

所謂的惰性查詢:publisher.objects.all()只是返回一個QuarySet(查詢結果集物件),並不會馬上執行sql,而是當呼叫QuerySet的時候才會執行。

>>> Author.objects.all()
(0.002) SELECT `hello_author`.`id`, `hello_author`.`name` FROM `hello_author` LIMIT 21; args=()
<QuerySet [<Author: Author object>]>

>>> Book.objects.all()
(0.002) SELECT `hello_book`.`id`, `hello_book`.`title`, `hello_book`.`publisher_id`, `hello_book`.`publisher_date` FROM `hello_book` LIMIT 21; args=()
<QuerySet [<Book: Book object>]>
刪除

delete方法

刪除id為1的書籍

'''刪除指定id的書籍'''

>>> Book.objects.filter(id=1).delete()
(0.003) SELECT `hello_book`.`id`, `hello_book`.`title`, `hello_book`.`publisher_
id`, `hello_book`.`publisher_date` FROM `hello_book` WHERE `hello_book`.`id` = 1; args=(1,)
(0.069) DELETE FROM `hello_book_authors` WHERE `hello_book_authors`.`book_id` IN (1); args=(1,)
(0.001) DELETE FROM `hello_book` WHERE `hello_book`.`id` IN (1); args=(1,)
(2, {'hello.Book': 1, 'hello.Book_authors': 1})
QuerySet常用的查詢相關的API

執行查詢的相關連結
QuerySet特點:
1.可迭代的
2.可切片的

# python manage.py shell
'''將查詢的結果儲存到一個變數中,通過檢視變數的型別發現返回值是QuerySet類。 '''
>>> from hello.models import *
>>> pub_list = Publisher.objects.all()
>>> type(pub_list)
<class 'django.db.models.query.QuerySet'>

>>> for pub in pub_list:
...  print(pub.name)
...

中國電子出版社
通過get獲取一個單一的物件

filter() 始終給你一個查詢集,即使只有一個物件滿足查詢條件 —— 這種情況下,查詢集將只包含一個元素。

如果你知道只有一個物件滿足你的查詢,你可以使用管理器的get() 方法,它直接返回該物件:

通過all獲取所有的物件

獲取一個表中所有物件的最簡單的方式是全部獲取。可以使用管理器的all() 方法:

>>> pub_list = Publisher.objects.all()

all()方法返回包含資料庫中所有物件的一個查詢集。

通過過濾器獲取特定的物件

all()方法 返回了一個包含資料庫表中所有記錄查詢集 。但在通常情況下,你往往想要獲取的是完整資料集的一個子集。

要建立這樣一個子集,你需要在原始的的查詢集上增加一些過濾條件。兩個最普遍的途徑是:

filter(**kwargs)
返回一個新的查詢集 ,它包含滿足查詢引數的物件。
exclude(**kwargs)
返回一個新的查詢集 ,它包含不滿足查詢引數的物件。
查詢引數(上面函式定義中的**kwargs)需要滿足特定的格式,下面欄位查詢一節中會提到。

舉個例子,要獲取年份為2006的所有文章的查詢集,可以使用filter()方法:

>>> Author_list = Author.objects.filter(id=1)
返回第一個、最後一條結果

first()
返回結果集的第一個物件, 當沒有找到時返回None.如果 QuerySet 沒有設定排序,則將會自動按主鍵進行排序
例:

>>> Author.objects.all()
>>> Author.objects.all().first()

last()
工作方式類似first(),只是返回的是查詢集中最後一個物件。

顯示指定欄位的值

values(*fields)
返回一個ValuesQuerySet —— QuerySet 的一個子類,迭代時返回字典而不是模型例項物件。而是一個可迭代的字典序列。

values_list
它與values()非常相似,只不過後者返回的結果是字典序列,而values_list()返回的是元組序列。

>>> Book.objects.filter(id=1).values('title','publisher_date')

<QuerySet [{'title': '岩石力學', 'publisher_date': datetime.date(2017, 11, 7)}]>


>>> Book.objects.filter(id=1).values_list('title','publisher_date')

<QuerySet [('岩石力學', datetime.date(2017, 11, 7))]>
QuerySet API參考
例項(單表查詢)
  • 查詢id為1的書籍,並只顯示資料名稱和出版日期

    >>> Book.objects.filter(id=1).values('title','publisher_date')
    <QuerySet [{'title': '岩石力學', 'publisher_date': datetime.date(2017, 11, 7)}]>
    >>> Book.objects.filter(id=1).values_list('title','publisher_date')
    <QuerySet [('岩石力學', datetime.date(2017, 11, 7))]>
  • 查詢所有的出版社資訊,並按照id降序排列,並嘗試使用reverse方法進行反向排序。

    >>> Publisher.objects.all().order_by('id').values('name')
    <QuerySet [{'name': '中國電子出版社'}, {'name': '中國工業出版社'}, {'name': '山
    西教育出版社'}]>
    >>> Publisher.objects.all().order_by('-id').values('name')
    <QuerySet [{'name': '山西教育出版社'}, {'name': '中國工業出版社'}, {'name': '中
    國電子出版社'}]>
    >>> Publisher.objects.all().order_by('id').values('name').reverse()
    <QuerySet [{'name': '山西教育出版社'}, {'name': '中國工業出版社'}, {'name': '中
    國電子出版社'}]>
  • 顯示所有的出版社的地址,不能重複

    >>> Publisher.objects.all().values('city')
    <QuerySet [{'city': '北京市'}, {'city': '天津市'}, {'city': '太原市'}, {'city':
    '太原市'}, {'city': '北京市'}, {'city': '北京市'}]>
    
    >>> Publisher.objects.all().values('city').distinct()
    
    <QuerySet [{'city': '北京市'}, {'city': '天津市'}, {'city': '太原市'}]>
  • 查詢北京市的出版社

    >>> Publisher.objects.filter(city='北京市').values('name')
    (0.002) SELECT `hello_publisher`.`name` FROM `hello_publisher` WHERE `hello_publ
    isher`.`city` = '北京市' LIMIT 21; args=('北京市',)
    <QuerySet [{'name': '中國電子出版社'}, {'name': '清華大學出版社'}, {'name': '北
    大教育出版社'}]>
  • 查詢北京市除外的出版社

    >>> Publisher.objects.exclude(city='北京市').values('name')
    
    <QuerySet [{'name': '中國工業出版社'}, {'name': '山西教育出版社'}, {'name': '山
    西大學出版社'}]>
  • 查詢男作者的數量

    >>> AuthorDetail.objects.filter(sex='男').count()
    (0.638) SELECT COUNT(*) AS `__count` FROM hello_authordetail` WHERE `hello_auth ordetail`.`sex` = '男'; args=('男',)
    3
例項(多表查詢)

多表查詢的技巧:
__ : 兩個下劃線可以生成連線查詢,查詢關聯的欄位資訊
_set:提供了物件訪問相關聯表資料的方法,但是這種方式只能是相關類訪問定義了關係的類(主鍵類訪問外來鍵類)

Publisher 類是Book類的主鍵類,

'''此處獲取Publisher物件只能通過get方法獲取,不能使用filter()'''

>>> pub_list = Publisher.objects.get(name='中國工業出版社')

>>> pub_list.book_set.all()
<QuerySet [<Book: Book object>]>

>>> pub_list.book_set.all().values('title')
<QuerySet [{'title': '流體力學'}]>
  • 查詢客戶的完整資訊

    '''AuthorDetail中的屬性author是與表Author關聯,如果直接列印author屬性,列印的是author_id.如果需要列印Author的屬性name,需要列印變數author__name'''
    
    >>> from hello.models import *
    >>> AuthorDetail.objects.values('sex','email','address','birthday','author')
    
    <QuerySet [{'address': '北京市海淀區梧桐路25號', 'birthday': '19920202', 'author': 1, 'sex': '男', 'email': '123456@qq.com'}, {'address': '上海市外灘32號', 'bir
    thday': '19921201', 'author': 2, 'sex': '男', 'email': '22222@qq.com'}, {'address': '廣州市廣陵大道21號', 'birthday': '19981232', 'author': 3, 'sex': '女', 'email': '33333@qq.com'}, {'address': '深圳市為民道11號', 'birthday': '19990303', 'author': 4, 'sex': '男', 'email': '44444@qq.com'}]>
    
    >>> AuthorDetail.objects.values('sex','email','address','birthday','author__name')
    
    <QuerySet [{'address': '北京市海淀區梧桐路25號', 'birthday': '19920202', 'author__name': 'jim', 'sex': '男', 'email': '123456@qq.com'}, {'address': '上海市外灘32號', 'birthday': '19921201', 'author__name': 'jim', 'sex': '男', 'email': '22222@qq.com'}, {'address': '廣州市廣陵大道21號', 'birthday': '19981232', 'author__name': 'lucy', 'sex': '女', 'email': '33333@qq.com'}, {'address': '深圳市為民道11號', 'birthday': '19990303', 'author__name': 'jick', 'sex': '男', 'email': '44444@qq.com'}]>
  • 查詢一本數書的作者姓名、出版社的名字

    >>> Book.objects.filter(title='岩石力學').values('title','authors','publisher')
    
    <QuerySet [{'publisher': 1, 'authors': 1, 'title': '岩石力學'}]>
    
    >>> Book.objects.filter(title='岩石力學').values('title','authors__name','publisher__name')
    
    <QuerySet [{'publisher__name': '中國電子出版社', 'title': '岩石力學', 'authors__name': 'jim'}]>
  • 查詢一個作者寫的所有的書籍

    >>> Book.objects.filter(authors__name='jim').values('title')
    
    <QuerySet [{'title': '岩石力學'}]>
例項(聚合和分組查詢)

聚合查詢
aggrate通過QuerySet進行計算,返回一個聚合值的字典,aggregate()每一個引數都指定一個包含在字典中的返回值。

  • 查詢某一個出版社出版書的數量

    利用QuerySet的API

    >>> from hello.models import *
    >>> Publisher.objects.filter(name='中國工業出版社').count()
    1
    

    利用聚合查詢aggregate

    '''匯入涉及到的模組'''
    >>> from django.db.models import *
    >>> Publisher.objects.filter(name='中國工業出版社').aggregate(Count('name'))
    
    {'name__count': 1}
  • 查詢某一個作者出版書籍的總價

    >>> Book.objects.filter(authors__name='jim').aggregate(Sum('price'))
    
    {'price__sum': Decimal('10.00')}

分組查詢annotate

可以為QuerySet中的每一個物件新增註解,可以通過計算機查詢的結果中的每一個物件所關聯的物件集合,從而得出總計價(也可是平均值或總和等)

  • 查詢所有的作者對應的所有出書的價格

    >>> Book.objects.values('authors__name').annotate(Sum('price'))
    
    <QuerySet [{'authors__name': 'jim', 'price__sum': Decimal('10.00')}, {'authors__
    name': 'lucy', 'price__sum': Decimal('10.00')}, {'authors__name': 'jick', 'price
    __sum': Decimal('10.00')}]>
  • 查詢所有出版社最便宜書籍的價格

    >>> Book.objects.values('publisher__name').annotate(Min('price'))
    
    <QuerySet [{'price__min': Decimal('10.00'), 'publisher__name': '中國電子出版社'}
    , {'price__min': Decimal('10.00'), 'publisher__name': '中國工業出版社'}, {'price
    __min': Decimal('10.00'), 'publisher__name': '山西教育出版社'}]>

資料模型

一對一:

作者模型:一個作者有姓名(一對一)
作者詳情模型:作者的詳情中有,性別、email地址、和出生日期、作者詳情模型和作者模型之間是一對一的關係

一對多:

出版商模型:出版商有名稱、地址、所在城市、省、國家、網站。
書籍模型:書籍有書名和出版商。一本書可以有多個作者,一個作者可以有多本書,所以作者和書籍的關係是多對多的關係【many-to-many】。一本書只能是一個出版商出版,一個出版商可以出版多本書,出版商和書籍是一對多的關係【one-to-many】,也被稱為外來鍵【foreignkey】

修改配置檔案


# models.py

from django.db import models

# Create your models here.
class Publisher(models.Model):
    name = models.CharField(max_length=30)
    address = models.CharField(max_length=50)
    city = models.CharField(max_length=60)
    state_province = models.CharField(max_length=30)
    country = models.CharField(max_length=50)
    website = models.URLField()


class Author(models.Model):
    name = models.CharField(max_length=30)


class AuthorDetail(models.Model):
    sex = models.CharField(max_length=1,choices=((0,'男'),(1,'女')))
    email = models.CharField()
    address = models.CharField(max_length=50)
    birthday = models.CharField()
    author = models.OneToOneField(Author)

class Book(models.Model):
    title = models.CharField(max_length=100)
    authors = models.ManyToManyField(Author)
    publisher = models.ForeignKey(Publisher)
    publisher_date = models.DateField()

程式碼簡介:

  • 每個資料模型型別都是Django.db.models.Models的子類。它的的父類Model中包含了所有必要的和資料庫互動的方法,並提供了一個簡潔漂亮的定義資料庫欄位的語法。
  • 每個模型相當於單個資料庫表(這條規則的例外情況是多對多的關係,多對多關係的時候會多生出一張表關係),每個屬性也是這個表的一個欄位,屬性名是欄位名,它的型別(例如CharField)相當於資料庫的欄位型別(例如varchar)。
  • 模型之間的關係:一對一(OneToOneField),一對多(ForeignKey)和多對多(ManyToManyField)

生成資料庫同步指令碼

> python manage.py makemigrations

同步資料庫

> python manage.py migrate

檢視資料庫的變化

同步資料庫之前:

這裡寫圖片描述

同步資料庫之後:

這裡寫圖片描述

新增加的表就是在models.py中的class。表名就是庫名,表中的欄位就是類的屬性。

常用的欄位型別:

欄位型別 含義
AutoField 一個根據實際ID自動增長的IntegerField
BigIntegerField 一個64位整數, 類似於一個 IntegerField
BinaryField 二進位制型別
BooleanField 布林欄位型別
CharField 字串型別
DateField 日期欄位
DateTimeField 日期時間欄位
DecimalField 精確小數字段
EmailField email欄位型別
FileField 檔案欄位型別
FloatField 浮點數字段型別
ImageField 圖片欄位型別
IntegerField 整數字段型別
IPAddressField IP欄位型別
SmallIntegerField 小整型欄位型別
TextField 文字欄位型別
URLField url欄位型別

更多型別型別連結

欄位選項

欄位選項名稱 含義
null 如果為True,Django將在資料庫中將空值儲存為NULL。預設值是 False
blank 如果為True,則該欄位允許為空白。 預設值是 False
choices 它是一個可迭代的結構(比如,列表或是元組),由可迭代的二元組組成(比如[(A, B), (A, B) …]),用來給這個欄位提供選擇項。
default 該欄位的預設值
help_text 額外的 ‘help’ 文字將被顯示在表單控制元件form中
primary_key 若為 True, 則該欄位會成為模型的主鍵欄位
unique 如果為 True, 這個欄位在表中必須有唯一值

參考文件

資料庫同步

'''如果資料庫中欄位增加或修改,需啊喲重新同步資料庫'''
D:\pythonwork\django\mysite>python manage.py makemigrations

You are trying to add a non-nullable field 'price' to book without a default; we
 can''t do that (the database needs something to populate existing rows).
Please select a fix:
 1) Provide a one-off default now (will be set on all existing rows with a null
value for this column)
'''第二點中提示退出設定增加欄位的預設值,在增加的欄位中新增引數default='''
 2) Quit, and let me add a default in models.py
Select an option: 2

D:\pythonwork\django\mysite>python35 manage.py makemigration

D:\pythonwork\django\mysite>python35 manage.py migrate

認識一個目錄

目錄名:migrations
作用:用來存放通過makemirgrations命令生成的資料庫指令碼。app目錄下面必須要有migrations的目錄且該目錄下必須存放__init__.py才能正常的使用資料庫的同步功能。

認識一張表(django_migrations)

記錄migrantions目錄下指令碼的使用情況

和資料庫相關的命令

flush:清空資料庫,恢復資料庫到最初的狀態
makemigrantions:生成資料同步的指令碼
migrate:同步資料庫
showmigrations:檢視生成的資料庫同步指令碼
sqlflush:檢視生成清空資料庫的指令碼
sqlmigrate:檢視資料庫同步的sql語句

使用原生的sql

使用原生sql的方式主要的目的是解決一些複雜的sql不能用ORM的方式寫出的問題。

extra:結果集修改器,一種提供額外查詢引數的機制
raw:執行原始sql並返回模式例項
直接自定義SQL(這種方式不依賴於model,前兩種方式要依賴於model)

extra例項

  • 查詢山西教育出版社出版所有價格大於10元的圖書

    >>> Book.objects.filter(publisher__name='山西教育出版社').extra(where=['price>10']).values('title')
    
    <QuerySet [{'title': '材料力學'}, {'title': '工程力學'}]>

    等價於

    >>> Book.objects.filter(publisher__name='山西教育出版社',price__gt=10).values('title')
    
    <QuerySet [{'title': '材料力學'}, {'title': '工程力學'}]>

使用raw

>>> Book.objects.raw('select * from hello_book')
<RawQuerySet: select * from hello_book>
>>> book_list = Book.objects.raw('select * from hello_book')
>>> for book in book_list:
...   print(book.title)
...
(0.003) select * from hello_book; args=()
岩石力學
流體力學
材料力學
工程力學

使用自定sql語句

>>> from django.db import connection
>>> cursor = connection.cursor()

'''插入資料'''
>>> cursor.execute('insert into hello_author(name) values("郭敬明")')
(0.087) insert into hello_author(name) values("郭敬明"); args=None
1

'''修改資料'''
>>> cursor.execute('update hello_author set name="韓寒" where name="郭敬明"')
(0.071) update hello_author set name="韓寒" where name="郭敬明"; args=None
1

'''刪除資料'''
>>> cursor.execute('delete from hello_author where name="韓寒"')
(0.205) delete from hello_author where name="韓寒"; args=None
1

'''查詢語句'''
>>> cursor.execute('select * from hello_author')
(0.002) select * from hello_author; args=None
4

'''獲取資料'''
>>> raw = cursor.fetchone()
>>> cursor.fetchone()
(2, 'jim')
>>> cursor.fetchone()
(3, 'lucy')
>>> cursor.fetchone()
(4, 'jick')
>>> cursor.fetchone()

模板

常用標籤

autoescape控制自動轉義

控制自動轉義是否可用.這種標籤帶有任何 on 或 off 作為引數的話,他將決定轉義塊內效果。該標籤會以一個endautoescape作為結束標籤.

當自動轉義生效時,所有變數內容會被轉義成HTML輸出(在所有過濾器生效後)這等同與手動將escape篩選器應用於每個變數。

唯一一個例外是,變數或者通過渲染變數的程式碼,或者因為它已經應用了 safe或escape過濾器,已經被標記為“safe”。

例如:
在views.py中

def test(request):
    value3 = "<a href=''>百度</a>"
    return render(request,'test.html',locals())

在test.html中

{% autoescape on %}
    {{ values4 }}
{% endautoescape %}
if 標籤的使用

格式:

{% if athlete_list %}
    Number of athletes: {{ athlete_list|length }}
{% elif athlete_in_locker_room_list %}
    Athletes should be out of the locker room soon!
{% else %}
    No athletes.
{% endif %}

例項:

#views.py

def test(request):
    number1 = 20
    return render(request,'test.html',locals())
#test.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>test-Title</title>
</head>
<body>
{% if number1 == 10 %}
    NUM:10
{% elif number1 == 20 %}
    NUM:20
{% else %}
    unknow
{% endif %}
</body>
</html>
#mysite/urls.py

from django.conf.urls import url,include
from django.contrib import admin


urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^', include('hello.urls')),
]
#hello/urls.py

from django.conf.urls import url
from hello import views


urlpatterns = [
       url(r'^hello/$', views.hello,{'a':123}),
       url(r'^test/$', views.test),
]

訪問測試:http://127.0.0.1:8000/test/

for標籤的設定
#views.py

def test(request):
    number1 = 20
    num_list = [1,2,3,4,5,6,7,8]
    return render(request,'test.html',locals())
#test.html

<ul>
{% for num1 in num_list %}
    <li>{{ num1 }}</li>
{% endfor %}
</ul>

訪問測試:http://127.0.0.1:8000/test/

verbatim標籤

停止模板引擎在該標籤的中渲染

{% verbatim %}
    {{if dying}}Still alive.{{/if}}
{% endverbatim %}
filter標籤

將字元全部小寫

{% filter force_escape|lower %}
    This text will be HTML-escaped, and will appear in all lowercase.
{% endfilter %}

全部轉化為大寫


{% filter force_escape|upper %}
    This text will be HTML-escaped, and will appear in all lowercase.
{% endfilter %}

內建過濾器

add

把add後的引數加給value

例如:

{{ value|add:"2" }}

如果 value 為 4,則會輸出 6.

過濾器首先會強制把兩個值轉換成Int型別。如果強制轉換失敗, 它會試圖使用各種方式吧兩個值相加。它會使用一些資料型別 (字串, 列表, 等等.) 其他型別則會失敗. Day of the month, 2 digits with leading zeros.

例如:,我們使用下面的值

{{ first|add:second }}

first 是 [1, 2, 3] ,second 是 [4, 5, 6], 將會輸出 [1, 2, 3, 4, 5, 6].

警告:

如果字串可以被強制轉換成int型別則會 summed,無法被轉換,則和上面的第一個例子一樣

addslashes在引號前面加上斜

例如,用於在CSV中轉義字串。

例如:
在views.py中

def test(request):
    number1 = 20
    num_list = [1,2,3,4,5,6,7,8]
    value = datetime.datetime.now()
    value1 = "I'm a boy"
    return render(request,'test.html',locals())

在test.html中

{{ value1|addslashes }}

如果value 是 “I’m using Django”, 輸出將變成 “I\’m using Django”.

date

例如:

{{ value|date:"D d M Y" }}

如果value是datetime物件(例如,datetime.datetime.now()的結果),輸出將是字串 ‘Wed 09 Jan 2008’

default

如果value的計算結果為False,則使用給定的預設值。否則,使用該value。

例如:
在views.py中

def test(request):
    value2 = ""
    return render(request,'test.html',locals())

在test.html中

{{ value2|default:"nothing" }}

如果value為”“(空字串),則輸出將為nothing。

default_if_none

如果(且僅當)value為None,則使用給定的預設值。否則,使用該value。

注意,如果給出一個空字串,預設值將不被使用。如果要回退空字串,請使用default過濾器。

例如:

{{ value|default_if_none:"nothing" }}

如果value為None,則輸出將為字串“nothing”

escape 轉義字串

轉義字串的HTML。具體來說,它使這些替換:

<轉換為&lt;
>轉換為&gt;
'(單引號)轉換為&#39;
"(雙引號)轉換為&quot;
&轉換為&amp;

轉義僅在字串輸出時應用,因此在連線的過濾器序列中escape的位置無關緊要:它將始終應用,就像它是最後一個過濾器。如果要立即應用轉義,請使用force_escape過濾器。

將轉義應用於通常會對結果應用自動轉義的變數只會導致一輪轉義完成。因此,即使在自動逃逸環境中使用此功能也是安全的。如果要應用多個轉義通過,請使用force_escape過濾器。

例如,您可以在autoescape關閉時將escape應用於欄位:

{% autoescape off %}
    {{ title|escape }}
{% endautoescape %}
filesizeformat 格式化檔案大小

格式化數值為“人類可讀”的檔案大小(例如’13 KB’, ‘4.1 MB’, ‘102 bytes’等)。

例如:

{{ value|filesizeformat }}
first 返回列表中的第一個值

返回列表中的第一項。

例如:

{{ value|first }}
last 返回列表中的最後一個值

返回列表中的最後一個專案。

例如:

{{ value|last }}
safe 字串不轉義

將字串標記為在輸出之前不需要進一步的HTML轉義。當自動轉義關閉時,此過濾器不起作用。

注意:如果您要連結過濾器,在safe後應用的過濾器可能會使內容再次不安全。例如,以下程式碼按原樣列印變數:

{{ var|safe|escape }}
truncatechars 擷取指定個數的字串

如果字串字元多於指定的字元數量,那麼會被截斷。截斷的字串將以可翻譯的省略號序列(“…”)結尾。

引數:要截斷的字元數

例如:

{{ value|truncatechars:5 }}

如果value是“Joel is a >,輸出將為“Joel i …”。
如果value是”123456789”,輸出結果為“12…”。輸出的總共的字串格式是5,包含三個省略號。

truncatewords 擷取指定個數的單詞

在一定數量的字後截斷字串。

引數:要截斷的字數

例如:

{{ value|truncatewords:2 }}

如果value 是 “Joel is a slug”, 輸出變為 “Joel is …”.

striptags

盡一切可能努力剝離所有[X] HTML標籤。
例如:

{{ value|striptags }}

如果 value 的值是 “Joel is a slug“, 輸出的結果是”Joel is a slug”.

無安全保證
請注意,striptags不會保證其輸出是HTML安全的,尤其是對於無效的HTML輸入。因此,NEVER將safe過濾器應用於striptags輸出。如果您正在尋找更強大的功能,可以使用bleach Python庫,特別是其clean方法。

模板的繼承

include標籤
  • 在模板的存放位置有sub.html和table.html兩個模板

    在sub.html中

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    這是一個子模板
    </body>
    </html>

    table.html在body中增加下面一行

    ......
    <br> {% include 'sub.html' %}

    訪問指定的頁面會看到子模板中的內容。如果子模板在table.html同級目錄下的dir1中,此處應該寫<br> {% include 'dir1\sub.html' %}

  • 傳遞變數到子模板中

    table.html在body中增加下面一行

    <br> {% include "dir1/sub.html" with person="Jane" greeting="Hello" %}

    sub.html在body中增加變數

    <body>
    這是一個子模板{{person}}
    </body>
block標籤

views.py中增加

def test1(request):
     return render(request,'test1.html',locals())

在hello/urls.py中設定

urlpatterns = [
       url(r'^hello/$', views.hello,{'a':123}),
       url(r'^test/$', views.test),
       url(r'^testbase/$', views.test1),
]

base.html中

<!DOCTYPE html>
<html lang="en">
<head>
    <link rel="stylesheet" href="style.css" />
    <title>{% block title %}我的基礎模板{% endblock %}</title>
</head>

<body>
    <div id="sidebar">
        {% block sidebar %}
        <ul>
            <li><a href="/">Home</a></li>
            <li><a href="/blog/">Blog</a></li>
        </ul>
        {% endblock %}
    </div>

    <div id="content">
        {% block content %}{% endblock %}
    </div>
</body>
</html>

test1.html中(base.html的子模板版)

{% extends "base.html" %}/span>

{% block title %}這是我的第I個子模板{% endblock %}

{% block content %}
這是子模板的內容
{% endblock %}

admin的後臺管理

兩種註冊方法

註冊方法

ModelAdmin objects
ModelAdmin類是模型在Admin 介面中的表示形式。通常,將它們在你的應用中的名為admin.py的檔案裡

from django.contrib import admin
from myproject.myapp.models import Author

class AuthorAdmin(admin.ModelAdmin):
    pass
admin.site.register(Author, AuthorAdmin)

如果對於預設的Admin 介面足夠滿意,那你根本不需要自己定義ModelAdmin 物件, 你可以直接註冊模型類而無需提供ModelAdmin 的描述

from django.contrib import admin
from myproject.myapp.models import Author

admin.site.register(Author)

例項

在檔案hello/admin.py中,

class PublisherAdmin(admin.ModelAdmin):
    list_display = ('name','address','city','state_province','country','website',)

admin.site.register(Author)
admin.site.register(Publisher,PublisherAdmin)
admin.site.register(AuthorDetail)
admin.site.register(Book)
註冊裝飾器
@admin.register(Publisher)
class PublisherAdmin(admin.ModelAdmin):
    list_display = ('name','address','city','state_province','country','website',)

admin.site.register(Author)
# admin.site.register(Publisher,PublisherAdmin)
admin.site.register(AuthorDetail)
admin.site.register(Book)

ModelAdmin 選項

list_display顯示指定的欄位

使用list_display 去控制哪些欄位會顯示在Admin 的修改列表頁面中。

list_display = ('name','address','city','state_province','country','website',)
search_fields指定搜尋的欄位

這裡寫圖片描述

search_fields = ('name','address')
list_filter指定列表過濾器

這裡寫圖片描述

list_filter = ('state_province',)
ordering排序
ordering = ('name',)

如果介面上有name欄位,會在子段的旁邊顯示上下箭頭(選擇升序或者降序)

編輯表單 fields/exclude

只能編輯的表單

fields = ('name','address')

除了指定的欄位之外的表單都能編輯

exclude = ('name','address')
fieldsets

介面顯示:
這裡寫圖片描述

fieldsets = (
        (None, {
            'fields': ('name', 'address', )
        }),
        ('Advanced options', {
            'classes': ('collapse',),
            'fields': ('city', 'state_province', 'country')
        }),
    )

使用表單 form

django表單系統中,所有的表單類都是作為django.forms.form的子類建立的。包括ModelForm

關於表單系統主要分為兩類,

基於django.forms.Form:所有表單類的父類
基於django.forms.ModelForm: 可以和模型類繫結的Form

不使用From的情況配置,新增出版社資訊

/hello/urls.py

from django.conf.urls import url
from hello import views


urlpatterns = [
       url(r'^hello/$', views.hello,{'a':123}),
       url(r'^test/$', views.test),
       url(r'^testbase/$', views.test1),
       url(r'^add_publisher/$', views.add_publisher,name='add_publisher'),

]

hello/views.py中增加函式


from hello.models import Publisher
.......

def add_publisher(request):
    if request.method == 'POST':
        # 如果是POST提交,去接受使用者提交的資料
        name = request.POST.get('name')
        address = request.POST.get('address')
        city = request.POST.get('city')
        state_province = request.POST.get('state_province')
        country = request.POST.get('country')
        website = request.POST.get('website')

        Publisher.objects.create(
            name = name,
            address = address,
            city = city,
            state_province = state_province,
            country = country,
            website = website,

        )
        return HttpResponse("新增出版社成功")
    else:
        # 否則將傳輸的資料列印
        return render(request,'add_publisher.html',locals())

templates目錄下增加add_publisher.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>新增出版社資訊</title>
</head>
<body>
<form  action="{% url 'add_publisher' %}"  method="post" >
    {% csrf_token %}
    名稱:<input type="text" name="name"><br>
    地址:<input type="text" name="address"><br>
    城市:<input type="text" name="city"><br>
    省份:<input type="text" name="state_province"><br>
    國家:<input type="text" name="country"><br>
    網站:<input type="text" name="website"><br>
    <input type="submit",name="提交"><br>

</form>
</body>
</html>

使用Django_Form

/hello/urls.py

from django.conf.urls import url
from hello import views


urlpatterns = [
       url(r'^hello/$', views.hello,{'a':123}),
       url(r'^test/$', views.test),
       url(r'^testbase/$', views.test1),
       url(r'^add_publisher/$', views.add_publisher,name='add_publisher'),

]

hello/forms.py

from django import forms

class PublisherForm(forms.Form):

    # label標籤代表的是在介面上顯示的資訊,預設情況下顯示的英文
    name = forms.CharField(label='姓名')
    address = forms.CharField(label='地址')
    city = forms.CharField(label='城市')
    state_province = forms.CharField(label='省份')
    country = forms.CharField(label='國家')
    website = forms.URLField(label='網站')

hello\view.py

from hello.forms import PublisherForm
from hello.models import Publisher

def add_publisher(request):
    if request.method == 'POST':
        # 如果是POST提交,去接受使用者提交的資料
        # 使用Django_form
        publisher_form = PublisherForm(request.POST)
        if publisher_form.is_valid():
            Publisher.objects.create(
                name = publisher_form.cleaned_data['name'],
                address = publisher_form.cleaned_data['address'],
                city = publisher_form.cleaned_data['city'],
                state_province = publisher_form.cleaned_data['state_province'],
                country = publisher_form.cleaned_data['country'],
                website = publisher_form.cleaned_data['website'],

            )
            return HttpResponse("新增出版社成功")


    else:
        # 否則將傳輸的資料列印
        publisher_form = PublisherForm()
        return render(request,'add_publisher.html',locals())

templates目錄下增加add_publisher.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>新增出版社資訊</title>
</head>
<body>
<form  action="{% url 'add_publisher' %}"  method="post" >
    {% csrf_token %}
    {{ publisher_form.as_p }}   // 將view.py中建立的表單物件傳輸到模版中,表單中的欄位會自動生成,as_p表示的是輸出的格式使用</p>標籤

    <input type="submit" name="提交"><br>

</form>
</body>
</html>

使用ModelForm

/hello/urls.py

from django.conf.urls import url
from hello import views


urlpatterns = [
       url(r'^hello/$', views.hello,{'a':123}),
       url(r'^test/$', views.test),
       url(r'^testbase/$', views.test1),
       url(r'^add_publisher/$', views.add_publisher,name='add_publisher'),

]

hello/forms.py

from django import forms
from hello.models import Publisher

class PublisherForm(forms.ModelForm):

    class Meta:
            model = Publisher
            exclude = ("id",)

hello\view.py

from hello.forms import PublisherForm
from hello.models import Publisher

def add_publisher(request):
    if request.method == 'POST':
        # 如果是POST提交,去接受使用者提交的資料
        # 使用Django ModelForm
        publisher_form = PublisherForm(request.POST)
        if publisher_form.is_valid():
            publisher_form.save()
            return HttpResponse("新增出版社成功")

    else:
        # 否則將傳輸的資料列印
        publisher_form = PublisherForm()
        return render(request,'add_publisher.html',locals())

templates目錄下增加add_publisher.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>新增出版社資訊</title>
</head>
<body>
<form  action="{% url 'add_publisher' %}"  method="post" >
    {% csrf_token %}
    {{ publisher_form.as_p }}   // 將view.py中建立的表單物件傳輸到模版中,表單中的欄位會自動生成,as_p表示的是輸出的格式使用</p>標籤

    <input type="submit" name="提交"><br>

</form>
</body>
</html>

參考文件

Django官網
理解Django裡的MTV開發模式
Django 1.8 中文站點
Django 1.11 中文站點

相關文章