Django簡介

Django簡介

MVC與MTV模型

  • MVC百度百科:全名Model View Controller,是模型(model)-視圖(view)-控制器(controller)的縮寫,一種軟件設計典範,用一種業務邏輯、數據、界面顯示分離的方法組織代碼,將業務邏輯彙集到一個部件裏面,在改進和個性化定製界面及用戶交互的同時,不須要從新編寫業務邏輯。html

  • 通俗解釋:一種文件的組織和管理形式!不要被縮寫嚇到了,這其實就是把不一樣類型的文件放到不一樣的目錄下的一種方法,而後取了個高大上的名字。固然,它帶來的好處有不少,好比先後端分離,鬆耦合等等。前端

  • MTV: 有些WEB框架以爲MVC的字面意思很彆扭,就給它改了一下。view再也不是HTML相關,而是主業務邏輯了,至關於控制器。html被放在Templates中,稱做模板,因而MVC就變成了MTV。這其實就是一個文字遊戲,和MVC本質上是同樣的,換了個名字和叫法而已,換湯不換藥。python

MVC

  • Web服務器開發領域裏著名的MVC模式,將web應用分爲如下三層:
    • 模型(Model)
    • 視圖(View)
    • 控制器(Controller)
  • 以上三層之間以一種插件式的、鬆耦合的方式鏈接在一塊兒:
    • 模型負責業務對象與數據庫的映射(ORM)
    • 視圖負責與用戶的交互(頁面)
    • 控制器接受用戶的輸入調用模型和視圖完成用戶的請求。
  • 其示意圖以下所示:

MTV

Django的MTV模式本質上和MVC是同樣的,也是爲了各組件間保持鬆耦合關係,只是定義上有些許不一樣,Django的MTV分別是指:mysql

M 表明模型(Model): 負責業務對象和數據庫的關係映射(ORM)。
T 表明模板 (Template):負責如何把頁面展現給用戶(html)。
V 表明視圖(View):   負責業務邏輯,並在適當時候調用Model和Template。

除了以上三層以外,還須要一個URL分發器,它的做用是將一個個URL的頁面請求分發給不一樣的View處理,View再調用相應的Model和Template,MTV的響應模式以下所示:jquery

用戶經過瀏覽器向咱們的服務器發起一個請求(request),這個請求會去訪問視圖函數,(若是不涉及到數據調用,那麼這個時候視圖函數返回一個模板也就是一個網頁給用戶),視圖函數調用模型,模型去數據庫查找數據,而後逐級返回,視圖函數把返回的數據填充到模板中,最後返回網頁給用戶。web

  • Django 的MTV模型組織

Django項目實例

安裝

python3.五、pip3及pycharm專業版可自行安裝。
例:windows cmd命令行自動安裝Pypi提供的最新版本。
pip3 install django正則表達式

配置環境變量

成功安裝Djangio後,若有須要,能夠將python的Scripts目錄加入到系統環境變量中,以便調用django-admin命令。sql

配置完成後,可直接在cmd任一路徑下運行django-admin help命令測試安裝和配置完成:
數據庫

建立django項目和應用

  • 在windows cmd命令行界面下,使用diango提供的命令建立diango項目以下:
    • django-admin startproject mysite
    • 其中mysite是項目名稱,可自行替換成你想創建的項目名。
  • 而在該項目下建立應用的命令是:
    • python manage.py startapp blog
    • 其中blog爲app,應用名稱,可自行替換成你想創建的應用名稱。
  • 啓動django項目的命令爲:
    • python manage.py runserver 8080
    • runserver 默認爲本機(127.0.0.1),後面跟的8080爲端口號,可根據實際環境替換。
  • 這樣一個簡單的原始的django就啓動起來了,咱們到瀏覽器輸入127.0.0.1:8080實際上訪問的就是django的這個項目,如圖:

通常開發使用pycharm(IDE)操做是點擊file-new project,選擇Django欄目;
右側選擇項目所在路徑,選擇項目使用的python版本環境(可選虛擬環境),
注意Location中選擇項目路徑的同時所選的目錄也就是項目的名稱,
More Settings欄可設置模板文件夾名,web應用名稱,勾選自動建立相關web應用文件夾等。
點擊右下方的Create按鈕建立。

Django自動生成相似下面的目錄結構:

  • 和項目同名的文件夾中存放的是
    • settings.py 配置文件;
    • urls.py url路由文件;
    • wsgi.py 網絡通訊接口模塊;
  • templates模板目錄下爲空,此目錄主要用於存放各個html模板文件。
  • 項目根目錄下的manage.py文件爲django項目的管理主程序,工具等。
  • 各個應用目錄(如我這邊的建立的應用名爲app01)下存放主要有:
    • views.py 爲處理業務邏輯;
    • tests.py 爲單元測試;
    • modes.py 爲處理數據庫;
  • 推薦在項目根目錄下自行創建起一個static的靜態文件,用於存放css,js,img,html等靜態文件。

  • 在每一個Django項目中能夠包含多個APP,至關於一個大型項目中的分系統、子模塊、功能部件等等,相互之間比較獨立,但也能夠有聯繫。
    • 全部的APP共享項目資源。

編寫路由(url控制器)

路由由urls文件進行處理,功能是將瀏覽器輸入的url映射到相應的(views)業務處理邏輯。
因爲和業務處理邏輯相關,也就是和views相關,因此在文件開頭就須要先導入對應app的views.py文件。

例:沒作增添以前的urls.py(包括了官方註釋)

"""tielemao URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/2.0/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  path('', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.urls import include, path
    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path

urlpatterns = [
    path('admin/', admin.site.urls),
]

增添路由條目後:

from django.contrib import admin
from django.urls import path

# 需先導入對應的app目錄中的views文件
from app01 import views

urlpatterns = [
    # admin爲後臺管理的路由,通常不會暴露出來,註釋掉居多
    # path('admin/', admin.site.urls),
    # 本身新增的路由條目,前半部分表示路徑的爲正則表達式,後半部分爲對應的業務邏輯函數
    path('index/', views.index),
]

編寫業務處理邏輯(views視圖函數)

urls.py中增添的路由條目中對應了相應的本身命名的業務邏輯函數,
也就是接下來你就須要爲此在相應的views.py文件增添上相應的視圖函數。

原始的views.py文件:

from django.shortcuts import render

# Create your views here.

增添相應函數後:

from django.shortcuts import render

# 導入HttpResponse模塊
from django.shortcuts import HttpResponse

# Create your views here.

# request參數按規範必須有,相似self的默認存在,名字能夠改,但不建議。
# 它裏面封裝了用戶請求的全部內容。
def index(request):
    # 能夠print打印request.POST或request.GET來查看到請求
    # print(request.POST)
    # print(request.GET)

    # 正常是不能直接返回字符串,必須使用Django提供的HttpResponse
    # 這個類封裝起來就能夠返回字符串了,這是Django的規則,不是python的。
    return HttpResponse("hello world!")

經過上面兩個簡單的步驟,將index這個url指向了views裏的index()函數,它接收用戶請求,並返回一個「hello world」字符串。
咱們就能夠啓動web服務演示一下了。

運行web服務

  • 命令行方式:python manage.py runserver 127.0.0.1:8000
  • pycharm中能夠經過在工具欄中找到編輯配置文件的選項,快速進行設置host和port後再點擊綠色三角形進行運行:

運行效果:

在瀏覽器中訪問http://127.0.0.1:8000

此時會出現404的錯誤信息,由於此時咱們訪問的地址並非index/,在開發過程當中,Django給出的這些錯誤信息很重要,仔細閱讀方便排錯,但一旦正式上線生產環境,就必定要關掉如此詳細的調錯信息功能,常見的錯誤就本身另寫html報錯頁面。

在地址欄中輸入http://127.0.0.1:8000/index/,訪問纔會出現己設置好的正常顯示的hello world!

返回HTML

上面例子返回給用戶的是一個字符串,真正的web應用確定是不會這樣作的,一般返回的都應該是一個HTML文件給用戶。那麼,咱們寫以下showtime函數和time.html的HTML文件,作爲一個用戶訪問獲取
當前時間的功能例子:

  • urls.py代碼以下:
from django.contrib import admin
from django.urls import path

# 需先導入對應的app目錄中的views文件
from app01 import views

urlpatterns = [
    # admin爲後臺管理的路由,通常不會暴露出來,註釋掉居多
    path('admin/', admin.site.urls),
    # 本身新增的路由條目,前半部分表示路徑的爲正則表達式,後半部分爲對應的業務邏輯函數
    path('index/', views.index),
    # 新增用戶訪問time/路由,獲取當前時間函數
    path('time/', views.showtime),
]
  • views.py代碼以下,增長一個showtime函數:
from django.shortcuts import render

# 導入HttpResponse模塊
from django.shortcuts import HttpResponse

# 導入時間模塊
import datetime

# Create your views here.

# request參數按規範必須有,相似self的默認存在,名字能夠改,但不建議。
# 它裏面封裝了用戶請求的全部內容。
def index(request):
    # 正常是不能直接返回字符串,必須使用Django提供的HttpResponse
    # 這個類封裝起來就能夠返回字符串了,這是Django的規則,不是python的。
    return HttpResponse("hello world!")

def showtime(request):
    now=datetime.datetime.now()
    ctime=now.strftime("%Y-%m-%d %X")
    return render(request, "time.html", {"ctime":ctime})

request,它是一個對象。
當中存儲了請求信息,好比請求路徑,請求方式,GET數據,POST數據...等等。
必需要接收一個request參數。
當你想返回一個html文件時,不是使用HttpResponse方法,而是使用render方法來渲染(打包)。
不過本質上render最終仍是使用了HttpResponse方法發送byte字節給瀏覽器的。

  • 模板templates目錄下,新建一個time.html:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    {# 由兩個大括號括起來裏面加個變量名,至關因而字典的鍵名,是django用於佔位輸出的語法 #}
    <h3>當前時間:{{ ctime }}</h3>
</body>
</html>

訪問效果以下:

settings.py設置模板文件夾

settings.py文件中有TEMPLATES變量,它是一個列表,列表中又存放了一個字典,其中一個鍵值對
'DIRS':[os.path.join(BASE_DIR, 'templates')]
效果就是默認設置了模板目錄是使用默認的項目文件夾下的templates目錄。
若是有特殊須要修改的就是在此改動。
另外django有一個好處,代碼更改以後,通常無需重啓web服務,它會自動加載最新代碼。

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, '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',
            ],
        },
    },
]

使用靜態文件

將html文件返回給用戶還不夠,前端三大塊,HTML、CSS、JS還有各類插件等,完整齊全才是一個好看的頁面。在django中,通常將靜態文件放在static目錄中。接下來,在項目根目錄下新建一個static目錄。
同時,我還在此目錄下創建起js,css,img子目錄和相關文件,如圖:

static這個靜態目錄名和Django默認設置的靜態目錄名別名一致,
在settings.py中可找到相關設置項,就是在結尾處再添加上新的一行表示告訴Django靜態目錄的路徑:

# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/2.0/howto/static-files/

STATIC_URL = '/static/'
# STATIC_URL表示的是引用別名(指針),不是具體的目錄
# 能夠改爲你想指定的名字,可是在相應的引用地方必須和它對應到

# 增長如下一段表示設置靜態目錄的路徑
STATICFILES_DIRS = (
    os.path.join(BASE_DIR, 'static'),
)
# 真實目錄名不要在html中寫死,而是寫成別名引用,
# 如此,目錄名就算有改動也只需改動此處便可。
# 另外,因爲此行是一個元組,別忘了後面還需加個逗號。

同理,在html文件中引用靜態文件,例如jquery.js文件以下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    {# 由兩個大括號括起來裏面加個變量名,至關因而字典的鍵名,是django用於佔位輸出的語法 #}
    <h3>當前時間:{{ ctime }}</h3>
    <script src="/static/js/jquery.js"></script>
</body>
</html>

主要看<script src="/static/js/jquery.js"></script>這一行,裏面的路徑並無寫死,而是使用了static/來代指了真實的靜態目錄。

接收用戶發送的數據(get和post請求)

至此,咱們作到了將一個要素齊全的HTML文件返還給了用戶瀏覽器。
但這還不夠,由於web服務器和用戶之間尚未動態交互。
下面咱們來設計一個login頁面,上面創建一個表單,讓用戶輸入用戶名和密碼,提交給login
這個url,服務器將接收到這些數據。

login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登陸</title>
</head>
<body>
    <form action="" method="post">
        {# 注意Django中有一個跨站請求保護機制,因此須要加如下一行 #}
        {% csrf_token %}
        用戶名:<input type="text" name="user" />
        密碼:<input type="password" name="pwd" />
        <input type="submit" value="提交" />
    </form>
</body>
</html>
  • 這其中牽涉到一個csrf的防禦機制
    • CSRF百度百科:CSRF(Cross-site request forgery)跨站請求僞造,也被稱爲「One Click Attack」或者Session Riding,一般縮寫爲CSRF或者XSRF,是一種對網站的惡意利用。儘管聽起來像跨站腳本(XSS),但它與XSS很是不一樣,XSS利用站點內的信任用戶,而CSRF則經過假裝來自受信任用戶的請求來利用受信任的網站。與XSS攻擊相比,CSRF攻擊每每不大流行(所以對其進行防範的資源也至關稀少)和難以防範,因此被認爲比XSS更具危險性。
  • 假如沒有加{% csrf_token %}這一行防禦,運行時將會報以下圖的錯誤:

  • urls.py中urlpatterns添加路由條目:
    path('login/', views.login),

  • views.py中添加login函數:
def login(request):
    if request.method=="POST":
        username = request.POST.get("user", None)
        password = request.POST.get("pwd", None)
        print("用戶名:", username,"密碼", password)
    return render(request, "login.html")

此邏輯處理將會在pycharm中能夠看到用戶輸入的用戶名密碼。

運行效果以下:
html頁面效果:

pycharm後端效果:

pycharm中能夠看到提交後的post請求數據後端都獲取到了。

返回動態頁面

咱們收到了用戶的數據,但返回給用戶的依然是個靜態頁面,一般頁面會根據用戶的數據,進行處理後在返回給用戶。
django採用本身的模板語言,相似jinja2,可根據提供的數據,替換掉HTML中的相應部分。

例:views.py文件修改以下:

# 建立一個用戶信息表,預設了兩個數據,將返回給瀏覽器展現給用戶
user_list = [
    {"user":"tielemao", "pwd":"12345"},
    {"user":"LiLei", "pwd":"abc123"},
]

def login(request):
    if request.method=="POST":
        username = request.POST.get("user", None)
        password = request.POST.get("pwd", None)
        temp = {"user":username, "pwd":password}
        user_list.append(temp)
    return render(request, "login.html", {"data":user_list})
# render接收的第三個參數是後臺返回給瀏覽器的數據,一個字典。
# data是字典的鍵,是你在login.html中自定義的指針名字,對應引用值。

而login.html相應修改:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登陸</title>
</head>
<body>
    <form action="" method="post">
        {# 注意Django中有一個跨站請求保護機制,因此須要加如下一行 #}
        {% csrf_token %}
        用戶名:<input type="text" name="user" />
        密碼:<input type="password" name="pwd" />
        <input type="submit" value="提交" />
    </form>

    <h2>用戶列表</h2>
    <table border="1">
        <thead>
            <th>用戶名</th>
            <th>密碼</th>
        </thead>
        <tbody>
            {% for line in data %}
            <tr>
                <td>{{ line.user }}</td>
                <td>{{ line.pwd }}</td>
            </tr>
            {% endfor %}
        </tbody>
    </table>
</body>
</html>

login.html中利用for循環將data(引用)迭代填入數據到表格。
訪問頁面並輸入一些數據測試效果以下:

效果就是用戶列表會隨着提交的數據而發生變化,算是一個簡單的動態頁面, 和用戶的交戶過程。

使用數據庫

上面咱們雖然和用戶交互得很好,但並無保存任何數據,頁面一旦關閉,或服務器重啓,一切都將回到原始狀態。
使用數據庫是正常最多見的,django經過自帶的ORM框架操做數據庫,而且自帶輕量級的sqlite3數據庫。此次咱們先來使用sqlite數據庫來演示,後面再學習詳細使用mysql。
首先是註冊app,不進行這一步的話django不會知道該給哪一個app建立表。

  • 在settings.py中註冊你的app:
# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'app01.apps.App01Config',
]

例,由於我以前執行了建立應用的命令,django2.06版本自動在建立應用的同時就幫我註冊了app,就是上面代碼中的app01.apps.App01Config。若是重複註冊一個app01,會在運行python manage.py makemigrationsw命令的時候報錯django.core.exceptions.ImproperlyConfigured: Application labels aren't unique, duplicates: app01

而後在settings中,配置數據庫相關的參數,此次使用自帶的sqlite,不須要修改。

# Database
# https://docs.djangoproject.com/en/2.0/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}
  • 編輯models.py,也就是MTV中的M。
from django.db import models

# Create your models here.

# 固定繼承models.Model這個類
class UserInfo(models.Model):
    id = models.AutoField(primary_key=True)
    user = models.CharField(max_length=32)
    pwd = models.CharField(max_length=32)

以上建立了三個字段,分別保存id,用戶名和密碼。

  • 經過命令建立數據庫的表:
    • python manage.py makemigrations
      • 注:migration譯做遷移
      • 注意此時運行完此命令只是翻譯了了sql語句,尚未真正將sql語句實行到數據庫中
        ```cmd
        E:\Django\tielemao>python manage.py makemigrations
        Migrations for 'app01':
        app01\migrations\0001_initial.py
    • Create model UserInfo
      ```

    • python manage.py migrate
      • 此命令執行後纔是真正在相應的數據庫中建立好了表。
      • 同時還會將diango一些認爲要建立的表建立上。
E:\Django\tielemao>python manage.py migrate
Operations to perform:
  Apply all migrations: admin, app01, auth, contenttypes, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying app01.0001_initial... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying auth.0009_alter_user_last_name_max_length... OK
  Applying sessions.0001_initial... OK
  • 使用sqlite3做爲數據庫的話,如今能夠在項目根目錄下看到有db.sqlite3文件
    • 可使用查看sqlite文件的軟件鏈接查看該數據庫驗證。
    • 例如使用navicat鏈接sqlite:

  • 修改views.py中的業務邏輯以下:
from django.shortcuts import render
# 導入models文件
from app01 import models

def login(request):
    if request.method=="POST":
        username = request.POST.get("user", None)
        password = request.POST.get("pwd", None)
        # 添加數據到數據庫
        models.UserInfo.objects.create(user=username, pwd=password)
    # 從數據庫中讀取全部數據
    user_list = models.UserInfo.objects.all()

    return render(request, "login.html", {"data":user_list})
# render接收的第三個參數是後臺返回給瀏覽器的數據,一個字典。
# data是字典的鍵,是你在login.html中自定義的指針名字,對應引用值。

重啓web服務,刷新瀏覽器頁面,以後和用戶交互的數據都能保存到數據庫中。
任什麼時候候均可以從數據庫中讀取數據,展現到頁面上。

至此,一個要素齊全,主體框架展現清晰的簡單django項目完成了。

【end】

參考引用:
http://www.liujiangblog.com/blog/3/

相關文章
相關標籤/搜索