django框架基礎

內容:css

1.課前複習html

2.django路由規則python

3.django視圖函數mysql

4.django ORMjquery

5.模板git

 

django預備知識:http://www.javashuo.com/article/p-gaxyavsw-bm.htmlweb

django基礎參考:http://www.cnblogs.com/wupeiqi/articles/5237704.html正則表達式

 

 

 

1、課前複習sql

1.HTTP協議消息格式數據庫

 1    請求(request):
 2         請求方法 路徑 HTTP/1.1\r\n
 3         k1:v1\r\n
 4         ...\r\n
 5         \r\n
 6         請求體        <-- 能夠有,能夠沒有
 7     
 8     響應(response):
 9         HTTP/1.1 狀態碼 狀態描述符\r\n
10         k1:v1\r\n
11         Content-Type: text/html; charset=utf8\r\n
12         \r\n
13         響應正文       <-- HTML內容

 

 

2.python的web框架本質

  • 收發socket消息 --> 按照HTTP協議消息格式去解析消息
  • 路徑和要執行的函數的對應關係 --> 主要的業務邏輯
  • 字符串替換 --> 模板(特殊符號 --> 數據)

 

 

3.一個完整的請求過程:

  • 啓動服務端,等待客戶端(用戶的瀏覽器)來鏈接
  • 在瀏覽器地址欄輸入URL,與服務端創建鏈接,瀏覽器發送請求
  • 服務端收到請求消息,解析請求消息,根據路徑和函數的對應關係,找到將要執行的函數
  • 執行函數,打開HTML文件,進行字符串替換,獲得一個最終要返回的HTML內容
  • 按照HTTP協議的消息格式要求,把HTML內容回覆給用戶瀏覽器(發送響應)
  • 瀏覽器收到響應的消息以後,按照HTML的規則渲染頁面.
  • 關閉鏈接

 

 

 

2、django路由系統

在django程序中,能夠經過urls.py文件對全部的url進行任務的分配,根據路由規則的定義選擇不一樣的業務處理函數進行處理,urls.py中規定的對應規則能夠說是路由系統(URLconf)

關於路由規則的詳細內容:http://www.cnblogs.com/liwenzhou/p/8271147.html

1.基本路由規則

基本格式(1.x版本):

1 from django.conf.urls import url
2 
3 urlpatterns = [
4      url(正則表達式, views視圖函數,參數,別名),
5 ]
  • 正則表達式:一個正則表達式字符串
  • views視圖函數:一個可調用對象,一般爲一個視圖函數或一個指定視圖函數路徑的字符串
  • 參數:可選的要傳遞給視圖函數的默認參數(字典形式)
  • 別名:一個可選的name參數

Django 2.0版本路由系統的寫法:

1 from django.urls import path
2 
3 urlpatterns = [
4     path('articles/', views.articles),
5     path('articles/<int:year>/', views.year_archive),
6     path('articles/<int:year>/<int:month>/', views.month_archive),
7     path('articles/<int:year>/<int:month>/<slug:slug>/', views.article_detail),
8 ]

 

 

2.路由系統正則表達式詳解

基礎樣例 - 分組匹配:

1 from django.conf.urls import url
2 from . import views
3 
4 urlpatterns = [
5     url(r'^articles/2003/$', views.special_case_2003),
6     url(r'^articles/([0-9]{4})/$', views.year_archive),
7     url(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive),
8     url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail),
9 ]

注意:

  • urlpatterns中的元素按照書寫順序從上往下逐一匹配正則表達式,一旦匹配成功則再也不繼續
  • 若要從URL中捕獲一個值,只須要在它周圍放置一對圓括號(分組匹配)
  • 不須要添加一個前導的反斜槓,由於每一個URL 都有。例如,應該是^articles 而不是 ^/articles
  • 每一個正則表達式前面的'r' 是可選的可是建議加上

 

上面的示例使用簡單的正則表達式分組匹配(經過圓括號)來捕獲URL中的值並以位置參數形式傳遞給視圖;在更高級的用法中,可使用分組命名匹配的正則表達式組來捕獲URL中的值並以關鍵字參數形式傳遞給視圖

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

分組命名匹配:

1 from django.conf.urls import url
2 from . import views
3 
4 urlpatterns = [
5     url(r'^articles/2003/$', views.special_case_2003),
6     url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),
7     url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.month_archive),
8     url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<day>[0-9]{2})/$', views.article_detail),
9 ]

這個實現與前面的示例徹底相同,只有一個細微的差異:捕獲的值做爲關鍵字參數而不是位置參數傳遞給視圖函數,另外注意不管哪一種方法每一個在路由中捕獲的參數都做爲一個普通的Python字符串傳遞給視圖

 

另外views.py中能夠給視圖函數的參數設置默認值:

 

 

3.django路由分發

1個Django 項目裏面有多個APP目錄你們共有一個 url容易形成混淆,因而路由分發讓每一個APP的擁有了本身單獨的url:

項目目錄下的urls.py:

1 from django.conf.urls import url, include
2 from django.contrib import admin
3 
4 urlpatterns = [
5     # 分發到APP的路由
6     url(r'^basic/', include('basic.urls')),
7     url(r'^app1/', include('app1.urls')),
8     url(r'^app2/', include('app2.urls')),
9 ]

basic這個APP下的urls.py:

1 from django.conf.urls import url
2 from basic import views
3 
4 urlpatterns = [
5     url(r'^index/', views.index),
6     url(r'^login/', views.login),
7     url(r'^register/', views.register),
8 ]

完成上述設置後,basic這個APP的路由只需在本身APP下的urls.py配置便可,訪問時前面帶上basic路徑便可

 

 

4.命名URL和URL反向解析

(1)前言

在使用Django 項目時,一個常見的需求是得到URL的最終形式,以用於嵌入到生成的內容中(視圖中和顯示給用戶的URL等)或者用於處理服務器端的導航(重定向等)。
人們強烈但願不要硬編碼這些URL(費力、不可擴展且容易產生錯誤)或者設計一種與URLconf 絕不相關的專門的URL 生成機制,由於這樣容易致使必定程度上產生過時的URL。
換句話講,須要的是一個DRY 機制。除了其它有點,它還容許設計的URL 能夠自動更新而不用遍歷項目的源代碼來搜索並替換過時的URL。
獲取一個URL 最開始想到的信息是處理它視圖的標識(例如名字),查找正確的URL 的其它必要的信息有視圖參數的類型(位置參數、關鍵字參數)和值。
Django 提供一個辦法是讓URL 映射是URL 設計惟一的地方。你填充你的URLconf,而後能夠雙向使用它:

  • 根據用戶/瀏覽器發起的URL 請求,它調用正確的Django 視圖,並從URL 中提取它的參數須要的值
  • 根據Django 視圖的標識和將要傳遞給它的參數的值,獲取與之關聯的URL

 

(2)命名URL和URL反向解析

前言中第一種方式是咱們在前面的章節中一直討論的用法,是直接得到url的最終形式,能夠稱之爲命名URL

而第二種方式叫作反向解析URL或者簡單的URL 反查
在須要URL 的地方,對於不一樣層級,Django 提供不一樣的工具用於URL 反查:

  • 在模板中:使用url模板標籤。
  • 在Python 代碼中:使用django.core.urlresolvers.reverse() 函數。
  • 在更高層的與處理Django 模型實例相關的代碼中:使用get_absolute_url() 方法。

反向解析URL本質上就是給url匹配模式起別名,而後用過別名拿到具體的URL路徑

用法以下:

 1 起別名: 在url匹配模式中,定義name="別名"
 2 
 3 1. 在模板語言裏面使用:
 4 {% url "別名" %} --> 獲得具體的URL路徑
 5 
 6 
 7 2. 在視圖中如何使用:
 8 from django.urls import reverse
 9 
10 reverse("別名") --> 獲得具體的URL路徑
11 
12 
13 3. 如何傳參數?
14 模板語言中:
15 {% url "別名" 2018 "nb" %}
16 
17 視圖函數中
18 傳位置參數:    reverse("別名", args=(2018, "nb"))
19 傳關鍵字參數: reverse("別名" kwargs={"year": 2018, "title": "nb"})
20 
21 
22 4. namespace
23 爲了防止不一樣的app下面的url匹配模式有重複的別名,能夠給app起別名

 

(3)實例以下:

urls.py:

1 urlpatterns = [
2     url(r'^admin/', admin.site.urls, name="admin"),
3     # 分發到APP的路由
4     url(r'^basic/', include('basic.urls', namespace="basic")),
5 ]
1 urlpatterns = [
2     url(r'^user_list/', views.user_list, name="user_list"),
3     url(r'^add_user/', views.add_user, name="add_user"),
4 ]

views.py:

 1 def user_list(request):
 2     res = models.UserInfo.objects.all()
 3     return render(request, "user/user_list.html", {"user_list": res})
 4 
 5 def add_user(request):
 6     err_msg = ""
 7     if request.method == "POST":
 8         new_name = request.POST.get("username", None)
 9         new_pwd = request.POST.get("password", None)
10         if new_name and new_pwd:
11             models.UserInfo.objects.create(username=new_name, password=new_pwd)
12             return redirect(reverse("basic:user_list"))
13         else:
14             err_msg = "用戶名或密碼不能爲空!"
15     return render(request, "user/add_user.html", {"error": err_msg})

HTML:

1 <a class="btn btn-default" href="{% url "basic:add_user" %}" role="button">添加用戶</a>

 

 

 

3、django視圖系統

視圖系統簡稱視圖,能夠是一個簡單的Python 函數,它接受Web請求而且返回Web響應。響應能夠是一張網頁的HTML內容,一個重定向,一個404錯誤,一個XML文檔,或者一張圖片. . . 是任何東西均可以。不管視圖自己包含什麼邏輯,都要返回響應。

約定將視圖放置在項目或APP目錄中的名爲views.py中(通常爲了模塊化都是放在APP的views裏)

關於視圖系統詳細:http://www.cnblogs.com/liwenzhou/articles/8305104.html

1.最簡單的視圖

不論什麼視圖都包含兩個對象:

  • request:用戶請求的相關全部信息,在django中是HttpRequest對象
  • response:響應信息(字符串 or HTML or 圖片、、、),在django中是HttpResponse對象

最簡單的視圖:

1 from django.shortcuts import HttpResponse
2 
3 def easy_view(request):
4     # 每一個視圖函數都使用HttpRequest對象做爲第一個參數,而且一般稱之爲request
5     return HttpResponse("hello world!")

視圖函數,圍繞着兩個對象進行:HttpResponse和HttpRequest

 

 

2.HttpRequest

(1)屬性

 1 request.path       獲取訪問文件路徑
 2 request.path_info       獲取用戶請求的路徑(不包含IP和端口和URL參數)
 3 request.method      獲取請求中使用的HTTP方式(POST/GET)
 4 request.body      含全部請求體信息 是bytes類型
 5 request.GET       GET請求的數據(類字典對象)  請求頭中的url中?後面拿值
 6 request.POST       POST請求的數據(類字典對象) 請求體裏拿值
 7 
 8 request.FILES:      包含全部上傳文件的類字典對象;FILES中的每個Key都是<input type="file" name="" />標籤中
 9                  name屬性的值,FILES中的每個value同時也是一個標準的python字典對象,包含下面三個Keys:
10                  filename:      上傳文件名,用字符串表示
11                  content_type:   上傳文件的Content Type
12                  content:       上傳文件的原始內容
13 
14 request.user:      是一個django.contrib.auth.models.User對象,表明當前登錄的用戶。若是訪問用戶當前
15                  沒有登錄,user將被初始化爲django.contrib.auth.models.AnonymousUser的實例。你
16                  能夠經過user的is_authenticated()方法來辨別用戶是否登錄:
17                  if req.user.is_authenticated();只有激活Django中的AuthenticationMiddleware
18                  時該屬性纔可用
19 
20 request.COOKIES    包含全部cookies的標準Python字典對象;keys和values都是字符串。
21 request.session     惟一可讀寫的屬性,表明當前會話的字典對象;本身有激活Django中的session支持時該屬性纔可用

 

屬性實例 - 上傳文件:

 1 def upload(request):
 2     """
 3     保存上傳文件前,數據須要存放在某個位置。默認當上傳文件小於2.5M時,django會將上傳文件的所有內容讀進內存。從內存讀取一次,寫磁盤一次。
 4     但當上傳文件很大時,django會把上傳文件寫到臨時文件中,而後存放到系統臨時文件夾中。
 5     :param request: 
 6     :return: 
 7     """
 8     if request.method == "POST":
 9         # 從請求的FILES中獲取上傳文件的文件名,file-name爲頁面上type=files類型input的name屬性值
10         filename = request.FILES["file-name"].name
11         # 在項目目錄下新建一個文件
12         with open(filename, "wb") as f:
13             # 從上傳的文件對象中一點一點讀
14             for chunk in request.FILES["file-name"].chunks():
15                 # 寫入本地文件
16                 f.write(chunk)
17         return HttpResponse("上傳OK")

 

(2)方法

1 request.GET.get('name', None)            拿到GET請求裏name的值(不存在就爲None)
2 request.POST.get('username', None)       拿到GET請求裏username的值(不存在就爲None)
3 若是某個鍵對應有多個值,則不能直接用get取值,須要用getlist,如:request.POST.getlist("hobby")
4
5 獲取請求路徑:
6 請求url: http://127.0.0.1:8000/index.html/23?a=1
7 request.path 結果: /index.html/23
8 request.get_full_path() 結果: /index.html/23?a=1

 

 

3.HttpResponse

對於HttpRequest請求對象來講,是由django自動建立的,可是,HttpResponse響應對象就必須咱們本身建立。每一個view請求處理方法必須返回一個響應。HttpResponse類在django.http.HttpResponse

能夠由HttpResponse對象上擴展出多種經常使用方法,以下所示

(1)HttpResponse函數

1 from django.shortcuts import HttpResponse
2 
3 
4 # 最簡單的視圖函數
5 def easy_view(request):
6     # 返回最簡單的一個響應(一個字符串): hello world!
7     return HttpResponse("hello world!")

 

補充 - JsonResponse

JsonResponse是HttpResponse的子類,專門用來生成JSON編碼的響應:

1 from django.http import JsonResponse
2 
3 response = JsonResponse({'foo': 'bar'})
4 print(response.content)
5 
6 b'{"foo": "bar"}'

默認只能傳遞字典類型,若是要傳遞非字典類型須要設置一下safe關鍵字參數:

response = JsonResponse([1, 2, 3], safe=False)

 

(2)render函數

做用:將特色頁面渲染後返回給瀏覽器

渲染 -> 給頁面中的參數賦值

render(request, template_name[, context])

結合一個給定的模板和一個給定的上下文字典,並返回一個渲染後的 HttpResponse 對象

參數以下:

  • request: 用於生成響應的請求對象
  • template_name:要使用的模板的完整名稱,可選的參數
  • context:添加到模板上下文的一個字典。默認是一個空字典。若是字典中的某個值是可調用的,視圖將在渲染模板以前調用它
  • content_type:生成的文檔要使用的MIME類型。默認爲DEFAULT_CONTENT_TYPE 設置的值
  • status:響應的狀態碼。默認爲200

render實例:

1 from django.shortcuts import render
2 
3 def my_view(request):
4     # 視圖的代碼寫在這裏
5     return render(request, 'index.html', {'foo': 'bar'})
1 def render(request, template_name, context=None, content_type=None, status=None, using=None):
2     """
3     Returns a HttpResponse whose content is filled with the result of calling
4     django.template.loader.render_to_string() with the passed arguments.
5     """
6     content = loader.render_to_string(template_name, context, request, using=using)
7     return HttpResponse(content, content_type, status)
render源碼

關於render:render方法主要是將從服務器提取的數據,填充到模板中,而後將渲染後的html靜態文件返回給瀏覽器

 

(3)redirect函數

redirect函數主要用於重定向,默認返回一個臨時的重定向;傳遞permanent=True 能夠返回一個永久的重定向

參數能夠是:

  • 一個模型:將調用模型的get_absolute_url() 函數
  • 一個視圖,能夠帶有參數:將使用urlresolvers.reverse 來反向解析名稱
  • 一個絕對的或相對的URL,將原封不動的做爲重定向的位置。

redirect實例: 

 1 from django.shortcuts import redirect
 2 
 3 # 經過一些對象來重定向(將調用該對象的get_absolute_url方法):
 4 def my_view(request):
 5     ...
 6     object = MyModel.objects.get(...)
 7     return redirect(object)
 8 
 9 # 傳遞視圖的名稱和可選參數來重定向(將使用reverse方法進行反向解析出url):
10 def my_view(request):
11     ...
12     return redirect('some-view-name', foo='bar')
13 
14 # 傳遞一個url重定向:
15 def my_view(request):
16     ...
17     return redirect('/some/url/')

對比render和redirect:

  • render: 只是返回頁面內容,可是未發送第二次請求
  • redirect:發送了第二次請求,url更新

另外:

臨時重定向(響應狀態碼:302)和永久重定向(響應狀態碼:301)對普通用戶來講是沒什麼區別的,它主要面向的是搜索引擎的機器人。

  • A頁面臨時重定向到B頁面,那搜索引擎收錄的就是A頁面
  • A頁面永久重定向到B頁面,那搜索引擎收錄的就是B頁面

 

(4)實戰 - 簡單登陸的完整示例 

HTML:

1 form表單日後端提交數據須要注意三點: 
2 1. form不是from,全部獲取用戶輸入的標籤都應該放在form裏面, 而且必需要有name屬性
3 2. action屬性控制往哪兒提交,method通常都設置成post
4 3. 提交按鈕必須是type=submit,不能是別的類型
 1 <!-- author: wyb -->
 2 <!DOCTYPE html>
 3 <html lang="en">
 4 <head>
 5     <meta charset="UTF-8">
 6     <!-- 移動端適配 -->
 7     <meta name="viewport" content="width=device-width, initial-scale=1">
 8     <title>登陸頁面</title>
 9     <!-- 引入normalize.css -->
10     <link href="https://cdn.bootcss.com/normalize/8.0.0/normalize.css" rel="stylesheet">
11     <!-- 最新版本的 Bootstrap 核心 CSS 文件 -->
12     <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css"
13           integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
14 
15     <style>
16         body{
17             background: #eeeeee;
18         }
19         #form-box{
20             margin-top: 199px;
21         }
22     </style>
23 </head>
24 <body>
25 
26 <div class="container-fluid">
27     <div class="row">
28         <div class="col-md-4 col-lg-3 col-md-offset-4">
29             <div id="form-box">
30                 <h3 class="text-center">請登陸</h3>
31                 <form class="form-horizontal" method="post" action="/baobao/">
32                     <div class="form-group">
33                         <label for="inputUsername" class="col-sm-3 control-label">用戶名</label>
34                         <div class="col-sm-9">
35                             <input name="username" type="text" class="form-control" id="inputUsername" placeholder="輸入用戶名">
36                         </div>
37                     </div>
38                     <div class="form-group">
39                         <label for="inputPassword3" class="col-sm-3 control-label">密碼</label>
40                         <div class="col-sm-9">
41                             <input name="password" type="password" class="form-control" id="inputPassword3" placeholder="輸入密碼">
42                         </div>
43                     </div>
44                     <div class="form-group">
45                         <div class="col-sm-offset-3 col-sm-9">
46                             <div class="checkbox">
47                                 <label>
48                                     <input type="checkbox"> 記住我
49                                 </label>
50                             </div>
51                         </div>
52                     </div>
53                     <div class="form-group">
54                         <div class="col-sm-offset-3 col-sm-9">
55                             <button type="submit" class="btn btn-primary btn-block">登陸</button>
56                         </div>
57                     </div>
58                 </form>
59             </div>
60         </div>
61     </div>
62 </div>
63 
64 
65 <!-- 引入jQuery -->
66 <script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>
67 <!-- 最新的 Bootstrap 核心 JavaScript 文件 -->
68 <script src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"
69         integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa"
70         crossorigin="anonymous"></script>
71 
72 </body>
73 </html>
登陸頁面

urls:

1 url(r'^login/', views.login),
2 url(r'^baobao/', views.baobao),

views(GET和POST分開寫):

 1 def login(request):
 2     return render(request, "login.html")
 3 
 4 
 5 def baobao(request):
 6     # 獲取用戶提交的數據
 7     # 獲取全部POST的數據: print(request.POST)
 8     username = request.POST.get("username", None)
 9     password = request.POST.get("password", None)
10     print(username, password)
11     # 作是否登陸成功的判斷
12     if username == "wyb" and password == "wyb666":
13         # 登陸成功
14         return HttpResponse("登陸成功!")
15     return HttpResponse("登陸失敗!")

views(GET和POST一塊兒寫):

 1 # 先把form表單的action屬性去掉(不寫就是往當前路由提交)
 2 
 3 # 而後修改login函數以下:
 4 def login(request):
 5     if request.method == "GET":
 6         # 若是是GET請求:
 7         return render(request, "login.html")
 8     else:
 9         # 若是是POST請求:
10         username = request.POST.get("username", None)
11         password = request.POST.get("password", None)
12         print(username, password)
13         # 作是否登陸成功的判斷
14         if username == "wyb" and password == "wyb666":
15             # 登陸成功
16             return HttpResponse("登陸成功!")
17         return HttpResponse("登陸失敗!")

views優化版:

 1 # render和redirect實例
 2 # 首先在login.html中的form表單結束以前插入一個p標籤(內容: {{ error}})
 3 # 而後修改login函數代碼以下:
 4 def login(request):
 5     error_msg = ""
 6     if request.method == "POST":
 7         # 若是是POST請求:
 8         username = request.POST.get("username", None)
 9         password = request.POST.get("password", None)
10         print(username, password)
11         # 作是否登陸成功的判斷
12         if username == "wyb" and password == "wyb666":
13             # 登陸成功
14             # return HttpResponse("登陸成功!")
15             # 回覆一個特殊的響應(重定向) 這個響應讓用戶的瀏覽器自動請求指定的url
16             return redirect("http://www.luffycity.com")
17         else:
18             # 登陸失敗
19             error_msg = "用戶名或密碼錯誤"
20     # 不是POST走這下面:
21     return render(request, "login.html", {"error": error_msg})

 

(5)CBV和FBV

以前寫過的都是基於函數的view,就叫FBV。還能夠把view寫成基於類的。

就拿上面寫的登錄爲例:

FBV版:

 1 # FBV版登錄
 2 def login(request):
 3     error_msg = ""
 4     if request.method == "POST":
 5         username = request.POST.get("username", None)
 6         password = request.POST.get("password", None) 7 
 7         if username == "wyb" and password == "safsfwefvs":
 8             return HttpResponse("登陸成功!")
 9         else:
10             error_msg = "登錄失敗: 用戶名或密碼錯誤"
11     return render(request, "user/login.html", {"error": error_msg})

 

CBV版:

 1 # CBV版登錄:
 2 from django.views import View
 3 
 4 class Login(View):
 5     def get(self, request):
 6         return render(request, "user/login.html")
 7 
 8     def post(self, request):
 9         username = request.POST.get("username", None)
10         password = request.POST.get("password", None)
11         if username == "wyb" and password == "sdfsadf":
12             return HttpResponse("登陸成功!")
13         else:
14             error_msg = "登錄失敗: 用戶名或密碼錯誤"
15             return HttpResponse(error_msg)

 

注意當使用CBV時,urls.py中也作對應的修改:

# urls.py中
url(r'^login/$', views.Login.as_view()),

 

 

 

4、django ORM

對象關係映射(Object Relational Mapping,簡稱ORM)模式是一種爲了解決面向對象與關係數據庫存在的互不匹配的現象的技術。

簡單的說,ORM是經過使用描述對象和數據庫之間映射的元數據,將程序中的對象自動持久化到關係數據庫中。

ORM在業務邏輯層和數據庫層之間充當了橋樑的做用

ORM詳細內容:http://www.cnblogs.com/liwenzhou/articles/8276526.html

1.ORM介紹

(1)django中的數據庫操做

到目前爲止,當咱們的程序涉及到數據庫相關操做時,咱們通常會這樣作:

  • 本身建立數據庫,設計表結構和字段
  • 使用 pymysql鏈接數據庫,並編寫數據訪問層代碼
  • 業務邏輯層去調用數據訪問層執行數據庫操做

django爲使用一種新的方式,即:關係對象映射(Object Relational Mapping,簡稱ORM)來完成上述的數據訪問層

  • PHP:activerecord
  • Java:Hibernate 
  • C#:Entity Framework

django中遵循 Code Frist 的原則,即:根據代碼中定義的類來自動生成數據庫表

 

(2)ORM優缺點

優勢:

  • 簡單,不用本身寫SQL語句
  • 開發效率高

缺點:

  • 須要記憶特殊的語法
  • 相對於大神的SQL語句,執行效率有差距


(3)ORM補充說明

ORM對應關係:

1 類 --->   數據表
2 對象 ---> 數據行
3 屬性 ---> 字段

實例以下:

 

ORM能作的事:

  • 操做數據表 --> 建立表/刪除表/修改表  --> 操做models.py裏面的類
  • 操做數據行 --> 數據的增刪改查

 

另外注意ORM不能建立數據庫,須要本身動手建立數據庫

 

 

2.django中ORM基礎配置

(1)建立數據庫
create database 數據庫名;

 

(2)設置數據庫配置

在Django項目中的settings.py中設置鏈接數據庫的相關配置(告訴Django鏈接哪個數據庫)

 1 # Database
 2 # https://docs.djangoproject.com/en/1.11/ref/settings/#databases
 3 
 4 # 默認使用sqlite數據庫
 5 # DATABASES = {
 6 #     'default': {
 7 #         'ENGINE': 'django.db.backends.sqlite3',
 8 #         'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
 9 #     }
10 # }
11 
12 # 數據庫相關配置:
13 DATABASES = {
14     'default': {
15         'ENGINE': 'django.db.backends.mysql',  # 鏈接的數據庫類型
16         'HOST': '127.0.0.1',  # 鏈接數據庫的地址
17         'PORT': 3306,  # 端口
18         'NAME': "django",  # 數據庫名稱
19         'USER': 'root',  # 用戶
20         'PASSWORD': 'root'  # 密碼
21     }
22 }

 

(3)__init__.py添加內容

告訴Django用pymysql代替默認的MySQLDB 鏈接MySQL數據庫
在項目/__init__.py文件中,寫下面兩句:

1 import pymysql
2 # 告訴Django用pymysql來代替默認的MySQLdb
3 pymysql.install_as_MySQLdb()

 

 

3.django中ORM使用步驟

(1)定義類

在app下面的models.py文件中定義一個類,這個類必須繼承models.Model

1 # ORM相關的只能寫在這個文件裏,寫到別的文件裏django找不到
2 from django.db import models
3 
4 
5 class UserInfo(models.Model):
6     id = models.AutoField(primary_key=True)     # 建立一個自增的主鍵字段
7     # 用戶名及密碼
8     username = models.CharField(null=False, max_length=20)
9     password = models.CharField(null=False, max_length=64)

 

(2)執行如下命令

  • python3 manage.py makemigrations -> 監視models文件的改變,將改變記錄下來到APP的migrations文件夾下
  • python3 manage.py migrate -> 把上述改動翻譯成SQL語句去數據庫執行

 

 

4.ORM字段

(1)Django ORM經常使用字段

  • AutoField -->  int自增列 必須填入參數primary_key=True
  • CharField -->  字符類型 varchar(xx) 必須提供max_length參數
  • TextField  -->  文本類型
  • ForeignKey --> 外鍵
  • ManyToManyField --> 多對多關聯
  • DateField  -->  日期字段  YYYY-MM-DD 至關於python的datetime.date()實例
  • DateTimeField  -->  日期時間字段 YYYY-MM-DD HH:MM 至關於python的datetime.datetime()實例
  • IntegerField  -->  整數類型
  1 AutoField(Field)
  2         - int自增列,必須填入參數 primary_key=True
  3 
  4     BigAutoField(AutoField)
  5         - bigint自增列,必須填入參數 primary_key=True
  6 
  7         注:當model中若是沒有自增列,則自動會建立一個列名爲id的列
  8         from django.db import models
  9 
 10         class UserInfo(models.Model):
 11             # 自動建立一個列名爲id的且爲自增的整數列
 12             username = models.CharField(max_length=32)
 13 
 14         class Group(models.Model):
 15             # 自定義自增列
 16             nid = models.AutoField(primary_key=True)
 17             name = models.CharField(max_length=32)
 18 
 19     SmallIntegerField(IntegerField):
 20         - 小整數 -32768 ~ 32767
 21 
 22     PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
 23         - 正小整數 0 ~ 32767
 24     IntegerField(Field)
 25         - 整數列(有符號的) -2147483648 ~ 2147483647
 26 
 27     PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
 28         - 正整數 0 ~ 2147483647
 29 
 30     BigIntegerField(IntegerField):
 31         - 長整型(有符號的) -9223372036854775808 ~ 9223372036854775807
 32 
 33     BooleanField(Field)
 34         - 布爾值類型
 35 
 36     NullBooleanField(Field):
 37         - 能夠爲空的布爾值
 38 
 39     CharField(Field)
 40         - 字符類型
 41         - 必須提供max_length參數, max_length表示字符長度
 42 
 43     TextField(Field)
 44         - 文本類型
 45 
 46     EmailField(CharField):
 47         - 字符串類型,Django Admin以及ModelForm中提供驗證機制
 48 
 49     IPAddressField(Field)
 50         - 字符串類型,Django Admin以及ModelForm中提供驗證 IPV4 機制
 51 
 52     GenericIPAddressField(Field)
 53         - 字符串類型,Django Admin以及ModelForm中提供驗證 Ipv4和Ipv6
 54         - 參數:
 55             protocol,用於指定Ipv4或Ipv6, 'both',"ipv4","ipv6"
 56             unpack_ipv4, 若是指定爲True,則輸入::ffff:192.0.2.1時候,可解析爲192.0.2.1,開啓此功能,須要protocol="both"
 57 
 58     URLField(CharField)
 59         - 字符串類型,Django Admin以及ModelForm中提供驗證 URL
 60 
 61     SlugField(CharField)
 62         - 字符串類型,Django Admin以及ModelForm中提供驗證支持 字母、數字、下劃線、鏈接符(減號)
 63 
 64     CommaSeparatedIntegerField(CharField)
 65         - 字符串類型,格式必須爲逗號分割的數字
 66 
 67     UUIDField(Field)
 68         - 字符串類型,Django Admin以及ModelForm中提供對UUID格式的驗證
 69 
 70     FilePathField(Field)
 71         - 字符串,Django Admin以及ModelForm中提供讀取文件夾下文件的功能
 72         - 參數:
 73                 path,                      文件夾路徑
 74                 match=None,                正則匹配
 75                 recursive=False,           遞歸下面的文件夾
 76                 allow_files=True,          容許文件
 77                 allow_folders=False,       容許文件夾
 78 
 79     FileField(Field)
 80         - 字符串,路徑保存在數據庫,文件上傳到指定目錄
 81         - 參數:
 82             upload_to = ""      上傳文件的保存路徑
 83             storage = None      存儲組件,默認django.core.files.storage.FileSystemStorage
 84 
 85     ImageField(FileField)
 86         - 字符串,路徑保存在數據庫,文件上傳到指定目錄
 87         - 參數:
 88             upload_to = ""      上傳文件的保存路徑
 89             storage = None      存儲組件,默認django.core.files.storage.FileSystemStorage
 90             width_field=None,   上傳圖片的高度保存的數據庫字段名(字符串)
 91             height_field=None   上傳圖片的寬度保存的數據庫字段名(字符串)
 92 
 93     DateTimeField(DateField)
 94         - 日期+時間格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]
 95 
 96     DateField(DateTimeCheckMixin, Field)
 97         - 日期格式      YYYY-MM-DD
 98 
 99     TimeField(DateTimeCheckMixin, Field)
100         - 時間格式      HH:MM[:ss[.uuuuuu]]
101 
102     DurationField(Field)
103         - 長整數,時間間隔,數據庫中按照bigint存儲,ORM中獲取的值爲datetime.timedelta類型
104 
105     FloatField(Field)
106         - 浮點型
107 
108     DecimalField(Field)
109         - 10進制小數
110         - 參數:
111             max_digits,小數總長度
112             decimal_places,小數位長度
113 
114     BinaryField(Field)
115         - 二進制類型
116 
117 字段合集
所有字段

 

(2) 自定義char字段

 1 class FixedCharField(models.Field):
 2     """
 3     自定義的char類型的字段類
 4     """
 5     def __init__(self, max_length, *args, **kwargs):
 6         self.max_length = max_length
 7         super(FixedCharField, self).__init__(max_length=max_length, *args, **kwargs)
 8 
 9     def db_type(self, connection):
10         """
11         限定生成數據庫表的字段類型爲char,長度爲max_length指定的值
12         """
13         return 'char(%s)' % self.max_length


(3)經常使用的字段參數

  • null 表示某個字段能夠爲空
  • default 爲字段設置默認值
  • unique 表示該字段在此表中惟一
  • db_index 爲此字段設置索引


DateField和DateTimeField纔有的參數:

  • auto_now_add=True --> 建立數據的時候自動把當前時間賦值
  • auto_add=True --> 每次更新數據的時候更新當前時間
  • 注意: 上述兩個不能同時設置!!!

 

(4)關係字段

ForeignKey:

外鍵類型在ORM中用來表示外鍵關聯關係,通常把ForeignKey字段設置在 '一對多'中'多'的一方。

字段參數以下:

  • to:設置要關聯的表
  • to_field:設置要關聯的表的字段
  • related_name:反向操做時,使用的字段名,用於代替原反向查詢時的'表名_set'
  • related_query_name:反向查詢操做時,使用的鏈接前綴,用於替換表名
  • on_delete:刪除關聯表中的數據時,當前表與其關聯的行的變化
  • db_constraint:是否在數據庫中建立外鍵約束,默認爲True,賦值爲False,表示爲軟關聯

 1 models.CASCADE:
 2 刪除關聯數據,與之關聯也刪除
 3 
 4 models.DO_NOTHING:
 5 刪除關聯數據,引起錯誤IntegrityError
 6 
 7 models.PROTECT:
 8 刪除關聯數據,引起錯誤ProtectedError
 9 
10 models.SET_NULL:
11 刪除關聯數據,與之關聯的值設置爲null(前提FK字段須要設置爲可空)
12 
13 models.SET_DEFAULT:
14 刪除關聯數據,與之關聯的值設置爲默認值(前提FK字段須要設置默認值)
15  
16 models.SET:
17 刪除關聯數據,
18 a. 與之關聯的值設置爲指定值,設置:models.SET(值)
19 b. 與之關聯的值設置爲可執行對象的返回值,設置:models.SET(可執行對象)
View Code

 

OneToOneField:
一對一字段  一般一對一字段用來擴展已有字段。

字段參數:

  • to: 設置要關聯的表
  • to_field: 設置要關聯的字段
  • on_delete: 同ForeignKey字段

示例:

 1 # 一對一的關聯關係多用在當一張表的不一樣字段查詢頻次差距過大的狀況下,將本能夠存儲在一張表的字段拆開放置在兩張表中,
 2 # 而後將兩張表創建一對一的關聯關係。
 3 
 4 class Author(models.Model):
 5 name = models.CharField(max_length=32)
 6 info = models.OneToOneField(to='AuthorInfo')
 7 
 8 class AuthorInfo(models.Model):
 9 phone = models.CharField(max_length=11)
10 email = models.EmailField()

 

ManyToManyField:
用於表示多對多的關聯關係。在數據庫中經過第三張表來創建關聯關係。

字段參數:

  • to: 設置要關聯的表
  • related_name: 同ForeignKey字段
  • related_query_name: 同ForeignKey字段
  • symmetrical: 僅用於多對多自關聯時,指定內部是否建立反向操做的字段。默認爲True
  • through:手動建立第三張表來管理多對多關係,此時需經過through來指定第三張表的表名
  • through_fields:設置關聯的字段
  • db_table:默認建立第三張表時,數據庫中表的名稱

 

實例:

1 class Person(models.Model):
2     name = models.CharField(max_length=16)
3     friends = models.ManyToManyField("self")
4     # 此時,person對象就沒有person_set屬性。
5 
6 class Person(models.Model):
7     name = models.CharField(max_length=16)
8     friends = models.ManyToManyField("self", symmetrical=False)
9     # 此時,person對象如今就可使用person_set屬性進行反向查詢。
 1 # 方式一:自行建立第三張表
 2 class Book(models.Model):
 3     title = models.CharField(max_length=32, verbose_name="書名")
 4 
 5 class Author(models.Model):
 6     name = models.CharField(max_length=32, verbose_name="做者姓名")
 7 
 8 
 9 # 本身建立第三張表,分別經過外鍵關聯書和做者
10 class Author2Book(models.Model):
11     author = models.ForeignKey(to="Author")
12     book = models.ForeignKey(to="Book")
13 
14     class Meta:
15         unique_together = ("author", "book")
16 
17 
18 # 方式二:經過ManyToManyField自動建立第三張表
19 class Book(models.Model):
20     title = models.CharField(max_length=32, verbose_name="書名")
21 
22 # 經過ORM自帶的ManyToManyField自動建立第三張表
23 class Author(models.Model):
24     name = models.CharField(max_length=32, verbose_name="做者姓名")
25     books = models.ManyToManyField(to="Book", related_name="authors")
26 
27 
28 # 方式三:設置ManyTomanyField並指定自行建立的第三張表
29 class Book(models.Model):
30     title = models.CharField(max_length=32, verbose_name="書名")
31 
32 # 本身建立第三張表,並經過ManyToManyField指定關聯
33 class Author(models.Model):
34     name = models.CharField(max_length=32, verbose_name="做者姓名")
35     books = models.ManyToManyField(to="Book", through="Author2Book", through_fields=("author", "book"))
36     # through_fields接受一個2元組('field1','field2'):
37     # 其中field1是定義ManyToManyField的模型外鍵的名(author),field2是關聯目標模型(book)的外鍵名。
38 
39 class Author2Book(models.Model):
40     author = models.ForeignKey(to="Author")
41     book = models.ForeignKey(to="Book")
42 
43     class Meta:
44         unique_together = ("author", "book")
45 
46 # 注意: 當咱們須要在第三張關係表中存儲額外的字段時,就要使用第三種方式
47 可是當咱們使用第三種方式建立多對多關聯關係時,就沒法使用set、add、remove、clear方法來管理多對多的關係了,
48 須要經過第三張表的model來管理多對多關係
多對多關聯關係

 

(5)元信息

ORM對應的類裏面包含另外一個Meta類,而Meta類封裝了一些數據庫的信息。主要字段以下:

  • db_table:ORM在數據庫中的表名默認是 app_類名,能夠經過db_table能夠重寫表名
  • index_together:聯合索引
  • unique_together:聯合惟一索引
  • ordering:指定默認按什麼字段排序
  • 只有設置了該屬性,咱們查詢到的結果才能夠被reverse()

例如設置重寫表名:

1 class Meta:
2     db_table = "xxx"

 

 

5.ORM操做

(1)操做數據表  -->  建立表/刪除表/修改表

使用ORM操做數據表實際上就是按上述ORM使用步驟來操做models.py裏面的類(把上面第一步替換成以下步驟):

  • 建立表:建立對應的類(定義類)
  • 刪除表:刪除對應的類(刪除類)
  • 修改表:修改對應的類(修改類)

 

(2)操做數據行  -->  數據的增刪改查

  • ORM查詢數據  models.UserInfo.objects.all()、
  • ORM添加數據  models.UserInfo.objects.create(name="張三")
  • ORM刪除數據  models.UserInfo.objects.get(id=user_id).delete()
  • ORM更新數據  models.UserInfo.objects.get(id=user_id).xxx = xxx -> save()

ORM操做數據詳細講解看這裏:http://www.javashuo.com/article/p-emhmbenx-bp.html

詳細以下:

 1 # 增:
 2 #
 3 # models.Tb.objects.create(c1='xx', c2='oo')  增長一條數據,能夠接受字典類型數據 **kwargs
 4 # obj = models.Tb(c1='xx', c2='oo')
 5 # obj.save()
 6 
 7 
 8 #
 9 #
10 # models.Tb.objects.all()  # 獲取所有
11 # models.Tb.objects.filter(name='seven')  # 獲取指定條件的數據
12 
13 #
14 #
15 # models.Tb1.objects.filter(name='seven').delete()  # 刪除指定條件的數據
16 
17 #
18 # models.Tb1.objects.filter(name='seven').update(gender='0')  # 將指定條件的數據更新,均支持 **kwargs
19 # obj = models.Tb1.objects.get(id=1)
20 # obj.c1 = '111'
21 # obj.save()                                                 # 修改單條數據
22         
23                     
24                     

 

 

6.ORM表關係

(1)三種表關係

ORM表關係有以下三種:

  • 一對多:models.ForeignKey(其餘表)
  • 多對多:models.ManyToManyField(其餘表)
  • 一對一:models.OneToOneField(其餘表)

實例以下:

一對多:當一張表中建立一行數據時,有一個單選的下拉框(能夠被重複選擇)
例如:建立用戶信息時候,須要選擇一個用戶類型【普通用戶】【會員用戶】【超級會員用戶】等

多對多:在某表中建立一行數據是,有一個能夠多選的下拉框
例如:建立用戶信息,須要爲用戶指定多個愛好 但同時一個愛好能夠被多個用戶選擇

一對一: 好比公司對應的董事長只能有一個

 

(2)詳細使用

  1 ForeignKey(ForeignObject) # ForeignObject(RelatedField)
  2         to,                         # 要進行關聯的表名
  3         to_field=None,              # 要關聯的表中的字段名稱
  4         on_delete=None,             # 當刪除關聯表中的數據時,當前表與其關聯的行的行爲
  5                                         - models.CASCADE,刪除關聯數據,與之關聯也刪除
  6                                         - models.DO_NOTHING,刪除關聯數據,引起錯誤IntegrityError
  7                                         - models.PROTECT,刪除關聯數據,引起錯誤ProtectedError
  8                                         - models.SET_NULL,刪除關聯數據,與之關聯的值設置爲null(前提FK字段須要設置爲可空)
  9                                         - models.SET_DEFAULT,刪除關聯數據,與之關聯的值設置爲默認值(前提FK字段須要設置默認值)
 10                                         - models.SET,刪除關聯數據,
 11                                                       a. 與之關聯的值設置爲指定值,設置:models.SET(值)
 12                                                       b. 與之關聯的值設置爲可執行對象的返回值,設置:models.SET(可執行對象)
 13 
 14                                                         def func():
 15                                                             return 10
 16 
 17                                                         class MyModel(models.Model):
 18                                                             user = models.ForeignKey(
 19                                                                 to="User",
 20                                                                 to_field="id"
 21                                                                 on_delete=models.SET(func),)
 22         related_name=None,          # 反向操做時,使用的字段名,用於代替 【表名_set】 如: obj.表名_set.all()
 23         related_query_name=None,    # 反向操做時,使用的鏈接前綴,用於替換【表名】     如: models.UserGroup.objects.filter(表名__字段名=1).values('表名__字段名')
 24         limit_choices_to=None,      # 在Admin或ModelForm中顯示關聯數據時,提供的條件:
 25                                     # 如:
 26                                             - limit_choices_to={'nid__gt': 5}
 27                                             - limit_choices_to=lambda : {'nid__gt': 5}
 28 
 29                                             from django.db.models import Q
 30                                             - limit_choices_to=Q(nid__gt=10)
 31                                             - limit_choices_to=Q(nid=8) | Q(nid__gt=10)
 32                                             - limit_choices_to=lambda : Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root')
 33         db_constraint=True          # 是否在數據庫中建立外鍵約束
 34         parent_link=False           # 在Admin中是否顯示關聯數據
 35 
 36 
 37     OneToOneField(ForeignKey)
 38         to,                         # 要進行關聯的表名
 39         to_field=None               # 要關聯的表中的字段名稱
 40         on_delete=None,             # 當刪除關聯表中的數據時,當前表與其關聯的行的行爲
 41 
 42                                     ###### 對於一對一 ######
 43                                     # 1. 一對一其實就是 一對多 + 惟一索引
 44                                     # 2.當兩個類之間有繼承關係時,默認會建立一個一對一字段
 45                                     # 以下會在A表中額外增長一個c_ptr_id列且惟一:
 46                                             class C(models.Model):
 47                                                 nid = models.AutoField(primary_key=True)
 48                                                 part = models.CharField(max_length=12)
 49 
 50                                             class A(C):
 51                                                 id = models.AutoField(primary_key=True)
 52                                                 code = models.CharField(max_length=1)
 53 
 54     ManyToManyField(RelatedField)
 55         to,                         # 要進行關聯的表名
 56         related_name=None,          # 反向操做時,使用的字段名,用於代替 【表名_set】 如: obj.表名_set.all()
 57         related_query_name=None,    # 反向操做時,使用的鏈接前綴,用於替換【表名】     如: models.UserGroup.objects.filter(表名__字段名=1).values('表名__字段名')
 58         limit_choices_to=None,      # 在Admin或ModelForm中顯示關聯數據時,提供的條件:
 59                                     # 如:
 60                                             - limit_choices_to={'nid__gt': 5}
 61                                             - limit_choices_to=lambda : {'nid__gt': 5}
 62 
 63                                             from django.db.models import Q
 64                                             - limit_choices_to=Q(nid__gt=10)
 65                                             - limit_choices_to=Q(nid=8) | Q(nid__gt=10)
 66                                             - limit_choices_to=lambda : Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root')
 67         symmetrical=None,           # 僅用於多對多自關聯時,symmetrical用於指定內部是否建立反向操做的字段
 68                                     # 作以下操做時,不一樣的symmetrical會有不一樣的可選字段
 69                                         models.BB.objects.filter(...)
 70 
 71                                         # 可選字段有:code, id, m1
 72                                             class BB(models.Model):
 73 
 74                                             code = models.CharField(max_length=12)
 75                                             m1 = models.ManyToManyField('self',symmetrical=True)
 76 
 77                                         # 可選字段有: bb, code, id, m1
 78                                             class BB(models.Model):
 79 
 80                                             code = models.CharField(max_length=12)
 81                                             m1 = models.ManyToManyField('self',symmetrical=False)
 82 
 83         through=None,               # 自定義第三張表時,使用字段用於指定關係表
 84         through_fields=None,        # 自定義第三張表時,使用字段用於指定關係表中那些字段作多對多關係表
 85                                         from django.db import models
 86 
 87                                         class Person(models.Model):
 88                                             name = models.CharField(max_length=50)
 89 
 90                                         class Group(models.Model):
 91                                             name = models.CharField(max_length=128)
 92                                             members = models.ManyToManyField(
 93                                                 Person,
 94                                                 through='Membership',
 95                                                 through_fields=('group', 'person'),
 96                                             )
 97 
 98                                         class Membership(models.Model):
 99                                             group = models.ForeignKey(Group, on_delete=models.CASCADE)
100                                             person = models.ForeignKey(Person, on_delete=models.CASCADE)
101                                             inviter = models.ForeignKey(
102                                                 Person,
103                                                 on_delete=models.CASCADE,
104                                                 related_name="membership_invites",
105                                             )
106                                             invite_reason = models.CharField(max_length=64)
107         db_constraint=True,         # 是否在數據庫中建立外鍵約束
108         db_table=None,              # 默認建立第三張表時,數據庫中表的名稱
View Code

 

(3)ORM多對多關聯查詢原理

多對多其實本質上要經過一張中間表來實現查找,中間表就以下圖中的author2book表:

 

 

(4)使用實例 - 圖書管理系統

表結構說明:

 1 圖書管理系統:
 2 主要是練習增刪改查操做以及表與表之間的關聯關係
 3 
 4 圖書管理系統的三種角色: 出版社、書、做者,這三種關係對應三張表
 5 
 6 表之間的關係
 7 一本書 只能 有一個出版社
 8 一本書 能有 多個做者
 9 一個做者 能寫 多本書
10 
11 出版社和書: 一對多 --> 外鍵(放在多的一端)
12 書和做者: 多對多 --> 用第三張表作關聯

ORM類以下:

 1 from django.db import models
 2 
 3 # 出版社
 4 class Publisher(models.Model):
 5     id = models.AutoField(primary_key=True)
 6     # 建立一個惟一的不爲空的字段
 7     name = models.CharField(max_length=64, null=False, unique=True)
 8 
 9     def __str__(self):
10         return "<Publisher Object: {}>".format(self.name)
11 
12 
13 #
14 class Book(models.Model):
15     id = models.AutoField(primary_key=True)
16     # 建立一個惟一的不爲空的字段
17     title = models.CharField(max_length=64, null=False, unique=True)
18     # 和出版社關聯的外鍵字段  存儲到數據中會自動加上_id變成publisher_id
19     publisher = models.ForeignKey(to="Publisher")
20 
21     def __str__(self):
22         return "<Book Object: {}>".format(self.title)
23 
24 
25 # 做者
26 class Author(models.Model):
27     id = models.AutoField(primary_key=True)
28     name = models.CharField(max_length=32, null=False, unique=True)
29     book = models.ManyToManyField(to="Book")    # 告訴ORM Author和Book是多對多關係 自動生成第三張表
30 
31     def __str__(self):
32         return "<Author Object: {}>".format(self.name)

添加書籍:

1 def add_book(request):
2     if request.method == "POST":
3         new_title = request.POST.get("book_title")
4         new_publisher_id = request.POST.get("publisher")  # 書籍關聯的出版社id
5         # print(new_title, new_publisher_id)
6         if new_title:
7             models.Book.objects.create(title=new_title, publisher_id=new_publisher_id)
8 
9     return redirect("/book/book_list/")

添加做者:

 1 def add_author(request):
 2     if request.method == "POST":
 3         # 注意post提交若是獲取多選要用getlist:
 4         author_name = request.POST.get("author_name")
 5         books = request.POST.getlist("books")           # book的一系列id
 6         # print(author_name, books)
 7         # 建立做者並把做者和書籍創建關係
 8         if author_name:
 9             new_author_obj = models.Author.objects.create(name=author_name)
10             new_author_obj.book.set(books)
11 
12     return redirect("/book/author_list/")

編輯書籍:

 1 def edit_book(request):
 2     if request.method == "POST":
 3         # 從提交的數據裏面取要編輯的書的如下內容: id 書名 書關聯的出版社
 4         edit_id = request.POST.get("id")
 5         new_title = request.POST.get("book_title")
 6         new_publisher_id = request.POST.get("publisher")
 7         # 書名爲空或書關聯的出版社不存在時重定向
 8         if not new_title or not models.Publisher.objects.filter(id=new_publisher_id):
 9             return redirect("/book/book_list/")
10         # 更新
11         edit_book_obj = models.Book.objects.filter(id=edit_id)[0]
12         if edit_book_obj:
13             edit_book_obj.title = new_title  # 更新書名
14             edit_book_obj.publisher_id = new_publisher_id  # 更新書籍關聯的出版社
15             # 將修改提交到數據庫
16             edit_book_obj.save()
17         else:
18             return HttpResponse("書籍不存在!")
19         # 返回書籍列表頁面,查看是否編輯成功
20         return redirect("/book/book_list/")

編輯做者:

 1 def edit_author(request):
 2     if request.method == "POST":
 3         # 從提交的數據裏面取要編輯的做者的如下內容: id 做者名 做者的一系列做品id
 4         edit_author_id = request.POST.get("author_id")
 5         new_author_name = request.POST.get("author_name")
 6         new_books = request.POST.getlist("books")
 7         print(edit_author_id, new_author_name, new_books)
 8         # 做者名爲空時重定向
 9         if not new_author_name:
10             return redirect("/book/author_list/")
11         # 更新
12         edit_author_obj = models.Author.objects.filter(id=edit_author_id)[0]
13         if edit_author_obj:
14             edit_author_obj.name = new_author_name        # 更新做者名
15             edit_author_obj.book.set(new_books)           # 更新做者關聯的做品
16             # 將修改提交到數據庫
17             edit_author_obj.save()
18         else:
19             return HttpResponse("做者不存在!")
20         # 返回書籍列表頁面,查看是否編輯成功
21         return redirect("/book/author_list/")

 

注意:以上添加功能和編輯功能沒有get請求,實際上在這裏後端省去了對get請求的處理(也就是添加和編輯沒有新頁面出現),

在這裏點擊添加或編輯後會在當前頁面(書籍列表頁或做者列表頁)出現一個彈框,點擊彈框的提交鍵便可向後端提交數據,

關於彈框的實現,能夠自定義彈框,也可使用Bootstrap的彈框樣式,我我的是直接使用Bootstrap的彈框

 

 

7.其餘

數據已有數據修改表結構問題:

 

 

 

5、模板

模板詳細內容:http://www.cnblogs.com/liwenzhou/p/7931828.html

1.經常使用語法

只須要記兩種特殊符號:{{ }}和 {% %}
變量相關的用{{}},邏輯相關的用{%%}

(1)變量相關

 1 {{ 變量名 }} -> 變量名由字母數字和下劃線組成
 2 點(.)在模板語言中有特殊的含義,用來獲取對象的相應屬性值
 3 
 4 {# 這是註釋 #}
 5 
 6 {# 取s中的第一個參數 #}
 7 {{ s.0 }}
 8 {# 取字典中key的值 #}
 9 {{ d.name }}
10 {# 取對象的name屬性 #}
11 {{ person_list.0.name }}
12 {# .操做只能調用不帶參數的方法 #}
13 {{ person_list.0.dream }}

 

(2)tags

 1 # for相關
 2 for循環:
 3     <ul>
 4     {% for user in user_list %}
 5         <li>{{ user.name }}</li>
 6     {% endfor %}
 7     </ul>
 8 
 9 for循環中可用的參數:
10     forloop.counter    當前循環的索引值(從1開始)
11     forloop.counter0    當前循環的索引值(從0開始)
12     forloop.revcounter    當前循環的倒序索引值(從1開始)
13     forloop.revcounter0    當前循環的倒序索引值(從0開始)
14     forloop.first    當前循環是否是第一次循環(布爾值)
15     forloop.last    當前循環是否是最後一次循環(布爾值)
16     forloop.parentloop    本層循環的外層循環
17 
18 for ... empty:
19     <ul>
20     {% for user in user_list %}
21         <li>{{ user.name }}</li>
22     {% empty %}
23         <li>空空如也</li>
24     {% endfor %}
25     </ul>
26 
27 
28 # if相關
29 if和else:
30     {% if 判斷條件 %}
31         xxx
32     {% else %}
33         xxx
34     {% endif %}
35 
36 
37 if,elif和else:
38     {% if 判斷條件 %}
39         xxx
40     {% elif 判斷條件 %}
41         xxx
42     {% else %}
43         xxx
44     {% endif %}
45 
46 另外if語句支持 andor、==、>、<、!=、<=、>=、innot inisis not判斷
47 if ... in 判斷:
48     {% if xxx in xxx %}
49         ...
50     {% endif %}
51 
52 
53 with: 定義一箇中間變量
54 {% with total=business.employees.count %}
55     {{ total }} employee{{ total|pluralize }}
56 {% endwith %}

 

(3)filter

filter主要是針對模板中的變量作一些額外的操做,語法: {{ value|filter_name:參數 }}

常見的以下:

  • default: {{ value|default: "nothing"}}  賦予默認值
  • length: {{ value|length }}  返回value的長度
  • filesizeformat:將值格式化爲一個可讀的文件尺寸 {{ value|filesizeformat }},若是value 是 123456789,輸出將會是 117.7 MB
  • slice - 切片:{{value|slice:"2:-1"}}
  • date - 格式化:{{ value|date:"Y-m-d H:i:s"}}
  • truncatechars - 截斷字符串:{{ value|truncatechars:9}},若是字符串字符多於指定的字符數量,將會被截斷。截斷的字符串將以可翻譯的省略號序列(「...」)結尾

 

safe - 關閉自動轉義

Django的模板中會對HTML標籤和JS等語法標籤進行自動轉義,緣由顯而易見,這樣是爲了安全(防止XSS攻擊)。可是有的時候咱們可能不但願這些HTML元素被轉義,好比咱們作一個內容管理系統,後臺添加的文章中是通過修飾的,這些修飾多是經過一個相似於FCKeditor編輯加註了HTML修飾符的文本,若是自動轉義的話顯示的就是保護HTML標籤的源文件。爲了在Django中關閉HTML的自動轉義有兩種方式,若是是一個單獨的變量咱們能夠經過過濾器「|safe」的方式告訴Django這段代碼是安全的沒必要轉義。

好比:

value = "<a href='#'>點我</a>"

1 {{ value|safe}}

 

自定義filter

自定義過濾器只是帶有一個或兩個參數的Python函數:

  • 變量(輸入)的值 - -不必定是一個字符串
  • 參數的值 - 這能夠有一個默認值,或徹底省略

例如,在過濾器{{var|foo:「bar」}}中,過濾器foo將傳遞變量var和參數「bar」

自定義filter代碼文件(py文件)要放在以下位置:

1 app/
2     __init__.py
3     models.py
4     templatetags/  # 在app下面新建一個package package
5         __init__.py
6         app_filters.py  # 建一個存放自定義filter的文件
7     views.py

編寫自定義filter:

 1 from django import template
 2 register = template.Library()
 3 
 4 # 帶參數的filter
 5 @register.filter(name="cut")
 6 def cut(value, arg):
 7     return value.replace(arg, "")
 8 
 9 # 不帶參數的filter
10 @register.filter(name="addSB")
11 def add_sb(value):
12     return "{} SB".format(value)

上述代碼註釋中的參數是指filter中的參數,而真正函數中的第一個參數(函數參數)永遠傳入的是value的值(|前面那個值)

使用自定義filter:

1 {# 先導入咱們自定義filter那個文件 #}
2 {% load app_filters %}
3 
4 {# 使用咱們自定義的filter #}
5 {{ somevariable|cut:"0" }}
6 {{ d.name|addSB }}

 

 

2.母版和繼承

(1)爲何要有母版和繼承

把多個頁面公用的部分提取出來,放在一個 母版 裏面。其餘的頁面只須要 繼承 母版就能夠了。能夠簡化代碼,寫更少的代碼

 

(2)具體使用步驟

  • 把公用的HTML部分(head、css、js、固定的HTML)提取出來,放到base.html文件中
  • 在base.html中,經過定義block,把每一個頁面不一樣的部分區分出來(大體劃分:頁面的特殊CSS、頁面的主體內容、頁面的特殊Js、頁面特殊組件)
  • 在具體的頁面中,先繼承母版
  • 而後block名去指定替換母版中相應的位置

base.html:

1 <!-- 頁面主體 -->
2 <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
3     {% block page-main %}
4     
5     {% endblock %}
6 </div>

具體的頁面中:

1 {# 繼承母版 #}
2 {% extends "base.html" %}
3 
4 {# 把本身頁面的內容塞到母版中相應的位置 #}
5 
6 {% block page-main %}
7     <h1>這是具體頁面</h1>
8 {% endblock %}

 

(3)使用的注意事項

  • {% extends 'base.html' %} --> 母版文件:base.html要加引號
  • {% extends 'base.html' %}必須放在子頁面的第一行!!!
  • 能夠在base.html中定義不少block,一般咱們會額外定義page-css和page-js兩個塊
  • view.py相應的函數中返回的是對應的子頁面文件 而不是base.html!

 

 

3.組件及靜態文件

(1)什麼是模板中的組件

能夠將經常使用的頁面內容如導航條,頁尾信息等組件保存在單獨的文件中,而後在須要使用的地方按以下語法導入便可:

1 {% include 'navbar.html' %}

 

(2)靜態文件導入問題

靜態文件:圖片、CSS、js

前面咱們的靜態文件的路徑都是寫死的,如過將static文件夾的名字改成static333,在代碼中咱們還要修改多處,這樣十分不方便,不過django中提供了方法,可讓HTML中的靜態文件路徑動態跟隨文件夾的名字變化而變化,從而實現動態導入

引入CSS:

1 {% load static %}
2 <link href="{% static 'CSS路徑' %}" rel="stylesheet">

引入圖片:

1 {% load static %}
2 <img src="{% static '圖片路徑' %}" alt="Hi" />

引用JS文件:

1 {% load static %}
2 <script src="{% static 'js路徑' %}"></script>

上述導入實例:

 

另外某個文件多處被用到能夠存爲一個變量:

1 {% load static %}
2 {% static "images/hi.jpg" as myphoto %}
3 <img src="{{ myphoto }}"></img>

 

(3)get_static_prefix

上面的導入靜態文件過程,是自動拼接static目錄名和後面的路徑,導入咱們也能夠手動拼接:

1 {% load static %}
2 <img src="{% get_static_prefix %}images/hi.jpg" alt="Hi!" />
3 
4 或者:
5 {% load static %}
6 {% get_static_prefix as STATIC_PREFIX %}
7 
8 <img src="{{ STATIC_PREFIX }}images/hi.jpg" alt="Hi!" />
9 <img src="{{ STATIC_PREFIX }}images/hi2.jpg" alt="Hello!" />

 

(4)自定義simpletag

相似上面的自定義filter不過使用起來更加自由

自定義simpletag文件(py文件)放在以下位置:

1 app/
2     __init__.py
3     models.py
4     templatetags/  # 在app下面新建一個package -> 放自定義filter文件和自定義simpletag文件
5         __init__.py
6         app_filters.py  # 建一個存放自定義filter的文件
7         app_simpletag.py  # 建一個存放自定義simpletag的文件
8     views.py

編寫自定義simpletag:

1 from django import template
2 
3 register = template.Library()
4 
5 @register.simple_tag(name="plus")
6 def plus(a, b, c):
7     return "{} + {} + {}".format(a, b, c)

使用自定義simpletag:

1 {% load app_simpletag.py %}
2 
3 {# simple tag #}
4 {% plus "1" "2" "abc" %}

 

(5)inclusion_tag

上面的自定義simpletag沒法返回HTML,要返回HTML就要使用inclusion_tag,使用方法以下:

 1 templatetags/my_inclusion.py:
 2 from django import template
 3 register = template.Library()
 4 
 5 @register.inclusion_tag('result.html')
 6 def show_results(n):
 7     n = 1 if n < 1 else int(n)
 8     data = ["第{}項".format(i) for i in range(1, n+1)]
 9     return {"data": data}
10 
11 
12 templates/result.html:13 <ul>
14   {% for choice in data %}
15     <li>{{ choice }}</li>
16   {% endfor %}
17 </ul>
18 
19 
20 templates/index.html:
21 <!DOCTYPE html>
22 <html lang="en">
23 <head>
24   <meta charset="UTF-8">
25   <meta http-equiv="x-ua-compatible" content="IE=edge">
26   <meta name="viewport" content="width=device-width, initial-scale=1">
27   <title>inclusion_tag test</title>
28 </head>
29 <body>
30 
31 {% load inclusion_tag_test %}
32 {% show_results 10 %}
33 
34 </body>
35 </html>
相關文章
相關標籤/搜索