MTV模式 php
著名的MVC模式:所謂MVC就是把web應用分爲模型(M),控制器(C),視圖(V)三層;他們之間以一種插件似的,鬆耦合的方式鏈接在一塊兒。html
模型負責業務對象與數據庫的對象(ORM),視圖負責與用戶的交互(頁面),控制器(C)接受用戶的輸入調用模型和視圖完成用戶的請求。前端
Django的MTV模式本質上與MVC模式沒有什麼差異,也是各組件之間爲了保持鬆耦合關係,只是定義上有些許不一樣,Django的MTV分別表明:python
Model(模型):負責業務對象與數據庫的對象(ORM)mysql
Template(模版):負責如何把頁面展現給用戶jquery
View(視圖):負責業務邏輯,並在適當的時候調用Model和Templategit
此外,Django還有一個url分發器,它的做用是將一個個URL的頁面請求分發給不一樣的view處理,view再調用相應的Model和Templateweb
一、建立Django項目正則表達式
django-admin startproject mysite
當前目錄下會生成一個 mysite的工程,目錄結構以下:sql
manage.py ----- Django項目裏面的工具,經過它能夠調用django shell和數據庫等。
settings.py ---- 包含了項目的默認設置,包括數據庫信息,調試標誌以及其餘一些工做的變量。
urls.py ----- 負責把URL模式映射到應用程序。
二、在mysite目錄下建立app應用
python manage.py startapp blog
三、啓動django項目
python manage.py runserver 8899 # ip:端口,默認本地ip
當咱們訪問:http://127.0.0.1:8899/ 時就能夠看到:
方法一:
靜態文件在單獨的app下:如 /app01/static/app01/JS/jquery-2.1.4.min.js (其中藍色app01目錄爲必須,但可改其餘名字,static文件夾也可改其餘名字)
# index.html
{% load static %} <script src="{% static 'app01/JS/jquery-2.1.4.min.js' %}"></script>
setting文件設置: (其中app01爲項目名字,static爲保存靜態文件的文件夾。)
STATIC_URL = '/whattttt/' # 前端使用前綴 STATICFILES_DIRS = ( os.path.join(BASE_DIR,'app01','static'), )
方法二: (同上述setting配置)
# index.html
<script src="/whattttt/app01/JS/jquery-2.1.4.min.js"></script>
方法三: 使用別名的形式
# index.html
{% load static %} <script src="{% static 'biemin/JS/jquery-2.1.4.min.js' %}"></script> <script src="/whattttt/biemin/JS/jquery-2.1.4.min.js"></script>
setting文件設置:
STATIC_URL = '/whattttt/' STATICFILES_DIRS = ( ('biemin',os.path.join(BASE_DIR,'app01','static','app01')), )
補充:
若是不想每次在模版中加載靜態文件都使用 {% load static%}
能夠在settings.py中的 TEMPLATES/OPTIONS添加'builtins':['django.templatetags.static']
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', ], #添加在這個位置 'builtins' : [ 'django.templatetags.static' ], }, }, ]
它的本質是URL模式以及要爲該URL模式調用的視圖函數之間的映射表
urlpatterns = [ url(正則表達式, view函數,參數,別名), ] urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^index/', views.index , {"a":'123'} , 'FFF'), ]
參數說明:
一個正則表達式字符串
一個可調用對象,一般爲一個視圖函數或一個指定視圖函數路徑的字符串
可選的要傳遞給視圖函數的默認參數(字典形式)
一個可選的name參數 (別名)
from django.conf.urls import url from app01 import views urlpatterns = [ url(r'^index/', views.index), 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), ]
無命名分組:
加了( )後,視圖函數須要添加一個形參,都爲字符串類型 !
urlpatterns = [ url(r'^articles/([0-9]{4})/$', views.year_archive), ] # 視圖函數: def year_archive(request,y): pass
命名分組 :
視圖函數形參名爲分組名 !
urlpatterns = [ url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive), ] # 視圖函數: def year_archive(request,year): pass
參數:
加上參數時,對應的視圖函數,必須加上一個形參,形參名必須與參數名相同!
若是 參數名與正則分組名字相同時,後面覆蓋前面!
urlpatterns = [ url(r'^index/', views.index , {"a":'123'} , 'FFF'), ]
別名:
加載時,一行一行去查找 url 中 name = ‘new_login’ 的行 , 而後替換 !
urlpatterns = [ url(r'^index/', views.login, name = 'new_login'), ] 用法: <form action = {% url 'new_login' %} >
URL映射分發 :
每當Django 遇到 include()時,它會去掉URL 中匹配的部分並將剩下的字符串發送給包含的URLconf 作進一步處理。
from django.conf.urls import url,include urlpatterns = [ url(r'^hot/', include('app01.urls')), ]
例子中的正則表達式沒有包含 $(字符串結束匹配符),可是包含一個末尾的斜槓。
from django.conf.urls import url,include from app01 import views urlpatterns = [ url(r'^all/', views.allpage), ]
頁面訪問 http://127.0.0.1:8000/hot/all 時觸發views.allpage
別名的應用:
urlpatterns = [ url(r'^index',views.index,name='bieming'), ] ################### def index(req): if req.method=='POST': username=req.POST.get('username') password=req.POST.get('password') if username=='alex' and password=='123': return HttpResponse("登錄成功") return render(req,'index.html') ##################### <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> {# <form action="/index/" method="post"> #} <form action="{% url 'bieming' %}" method="post"> 用戶名:<input type="text" name="username"> 密碼:<input type="password" name="password"> <input type="submit" value="submit"> </form> </body> </html> ####################### settings 中註釋掉: csrf該行進行測試demo MIDDLEWARE = [ # 'django.middleware.csrf.CsrfViewMiddleware', ]
http請求中產生兩個核心對象:
http請求:HttpRequest對象
http響應:HttpResponse對象
所在位置:django.http
視圖函數接收的參數request就是HttpRequest 檢測方法:isinstance(request,HttpRequest)
HttpRequest對象的屬性:
# path: 請求頁面的全路徑,不包括域名 # # method: 請求中使用的HTTP方法的字符串表示。全大寫表示。例如 # # if req.method=="GET": # # do_something() # # elseif req.method=="POST": # # do_something_else() # # GET: 包含全部HTTP GET參數的類字典對象 # # POST: 包含全部HTTP POST參數的類字典對象 # # 服務器收到空的POST請求的狀況也是可能發生的,也就是說,表單form經過 # HTTP POST方法提交請求,可是表單中可能沒有數據,所以不能使用 # if req.POST來判斷是否使用了HTTP POST 方法;應該使用 if req.method=="POST" # # # # COOKIES: 包含全部cookies的標準Python字典對象;keys和values都是字符串。 # # FILES: 包含全部上傳文件的類字典對象;FILES中的每個Key都是<input type="file" name="" />標籤中 name屬性的值,FILES中的每個value同時也是一個標準的python字典對象,包含下面三個Keys: # # filename: 上傳文件名,用字符串表示 # content_type: 上傳文件的Content Type # content: 上傳文件的原始內容 # # # user: 是一個django.contrib.auth.models.User對象,表明當前登錄的用戶。若是訪問用戶當前 # 沒有登錄,user將被初始化爲django.contrib.auth.models.AnonymousUser的實例。你 # 能夠經過user的is_authenticated()方法來辨別用戶是否登錄: # if req.user.is_authenticated();只有激活Django中的AuthenticationMiddleware # 時該屬性纔可用 # # session: 惟一可讀寫的屬性,表明當前會話的字典對象;本身有激活Django中的session支持時該屬性纔可用。
HttpRequest對象的方法:
get_full_path() 好比:http://127.0.0.1:8000/index33/?name=123 ,req.get_full_path() 獲得的結果就是/index33/?name=123
HttpResponse對象:
對於HttpRequest對象來講,是由django自動建立的,可是,HttpResponse對象就必須咱們本身建立。
每一個view請求處理方法必須返回一個HttpResponse對象。
HttpResponse 類在 django.http.HttpResponse
在HttpResponse對象上擴展的經常使用方法:
頁面渲染:render,render_to_response,
頁面跳轉:redirect
locals(): 能夠直接將函數中全部的變量傳給模板
from django.shortcuts import render,HttpResponse,redirect,render_to_response import time def index(request): times = time.time() return render(request,'index.html',{"times":times}) # 頁面渲染 return render(request,'index.html',locals()) # 頁面渲染 , HTML文件路徑在Setting文件中作了拼接處理! return render_to_response('index.html',locals()) # 頁面渲染 , 能夠不用填寫request return redirect('/login') # 跳轉
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>{{ times }}</h1> </body> </html>
1. django默認支持sqlite,mysql, oracle,postgresql數據庫。
<1> sqlite
django默認使用sqlite的數據庫,默認自帶sqlite的數據庫驅動
引擎名稱:django.db.backends.sqlite3
<2>mysql
引擎名稱:django.db.backends.mysql
2. mysql驅動程序
MySQLdb(mysql python)
mysqlclient
MySQL
PyMySQL(純python的mysql驅動程序)
3. 在django的項目中會默認使用sqlite數據庫,在settings裏有以下設置:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
若是咱們想要更改數據庫爲MYSQL,須要修改以下:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME':'dbname',
'USER': 'root',
'PASSWORD': 'xxx',
'HOST': '',
'PORT': '',
}
}
注意:NAME即數據庫的名字,在mysql鏈接前該數據庫必須已經建立,而上面的sqlite數據庫下的db.sqlite3則是項目自動建立
USER和PASSWORD分別是數據庫的用戶名和密碼。
設置完後,再啓動咱們的Django項目前,咱們須要激活咱們的mysql。
而後,啓動項目,會報錯:no module named MySQLdb
這是由於django默認你導入的驅動是MySQLdb,但是MySQLdb對於py3有很大問題,因此咱們須要的驅動是PyMySQL
因此,咱們只須要找到項目名文件下的__init__,在裏面寫入:
import pymysql
pymysql.install_as_MySQLdb()
問題就解決了!
這時就能夠正常啓動了。
但此時數據庫內並無內容,咱們須要作數據庫的同步:
數據庫的同步:
python manage.py makemigrations
python manage.py migrate
添加日誌記錄:(顯示每次執行的SQL語句)
LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'handlers': { 'console':{ 'level':'DEBUG', 'class':'logging.StreamHandler', }, }, 'loggers': { 'django.db.backends': { 'handlers': ['console'], 'propagate': True, 'level':'DEBUG', }, } }
4.2 Django的ORM(關係對象映射)
4.2.1 模型類的定義(一)
用於實現面向對象編程語言裏不一樣類型系統的數據之間的轉換,換言之,就是用面向對象的方式去操做數據庫的建立表以及增刪改查等操做。
優勢:1 ORM使得咱們的通用數據庫交互變得簡單易行,並且徹底不用考慮該死的SQL語句。快速開發,由此而來。
2 能夠避免一些新手程序猿寫sql語句帶來的性能問題。
缺點:1 性能有所犧牲,不過如今的各類ORM框架都在嘗試各類方法,好比緩存,延遲加載登來減輕這個問題。效果很顯著。
2 對於個別複雜查詢,ORM仍然力不從心,爲了解決這個問題,ORM通常也支持寫raw sql。
下面要開始學習Django ORM語法了,爲了更好的理解,咱們來作一個基本的 書籍/做者/出版商 數據庫結構。 咱們這樣作是由於 這是一個衆所周知的例子,不少SQL有關的書籍也經常使用這個舉例。
實例:咱們來假定下面這些概念,字段和關係
做者模型:
一個做者有姓名。
做者詳細模型:
把做者的詳情放到詳情表,包含性別,email地址和出生日期,做者詳情模型和做者模型之間是一對一的關係(one-to-one)(相似於每一個人和他的身份證之間的關係),
在大多數狀況下咱們沒有必要將他們拆分紅兩張表,這裏只是引出一對一的概念。
出版商模型:
出版商有名稱,地址,所在城市,省,國家和網站。
書籍模型:
書籍有書名和出版日期,一本書可能會有多個做者,一個做者也能夠寫多本書,因此做者和書籍的關係就是多對多的關聯關係(many-to-many),
一本書只應該由一個出版商出版,因此出版商和書籍是一對多關聯關係(one-to-many),也被稱做外鍵。
from django.db import models class Publisher(models.Model): name = models.CharField(max_length=30, verbose_name="名稱") 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 Meta: verbose_name = '出版商' verbose_name_plural = verbose_name def __str__(self): return self.name class Author(models.Model): name = models.CharField(max_length=30) def __str__(self): return self.name class AuthorDetail(models.Model): sex = models.BooleanField(max_length=1, choices=((0, '男'),(1, '女'),)) email = models.EmailField() address = models.CharField(max_length=50) birthday = models.DateField() author = models.OneToOneField(Author) class Book(models.Model): title = models.CharField(max_length=100) authors = models.ManyToManyField(Author) publisher = models.ForeignKey(Publisher) publication_date = models.DateField() price=models.DecimalField(max_digits=5,decimal_places=2,default=10) def __str__(self): return self.title
默認狀況下,Django 會給每一個模型添加下面這個字段:
id = models.AutoField(primary_key=True)
完成後,記得在settings 裏的INSTALLED_APPS中加入'app01',而後同步數據庫:
INSTALLED_APPS = [ .... 'app01', ]
模型之間的三種關係:一對一,一對多,多對多。
一對一:實質就是在主外鍵(author_id就是foreign key)的關係基礎上,給外鍵加了一個UNIQUE的屬性;
一對多:就是主外鍵關係;
多對多: book類裏定義了一個多對多的字段authors,可是並沒在book表中,這是由於建立了一張新的表:
模型的經常使用字段類型以及參數:
# AutoField # 一個 IntegerField, 添加記錄時它會自動增加. 你一般不須要直接使用這個字段; 若是你不指定主鍵的話,系統會自動添加一個主鍵字段到你的 model.(參閱 _自動主鍵字段) # BooleanField # A true/false field. admin 用 checkbox 來表示此類字段. # CharField # 字符串字段, 用於較短的字符串. # # 若是要保存大量文本, 使用 TextField. # # admin 用一個 <input type="text"> 來表示此類字段 (單行輸入). # # CharField 要求必須有一個參數 maxlength, 用於從數據庫層和Django校驗層限制該字段所容許的最大字符數. # CommaSeparatedIntegerField # 用於存放逗號分隔的整數值. 相似 CharField, 必需要有 maxlength 參數. # DateField # 一個日期字段. 共有下列額外的可選參數: # # Argument 描述 # auto_now 當對象被保存時,自動將該字段的值設置爲當前時間.一般用於表示 "last-modified" 時間戳. # auto_now_add 當對象首次被建立時,自動將該字段的值設置爲當前時間.一般用於表示對象建立時間. # admin 用一個文本框 <input type="text"> 來表示該字段數據(附帶一個 JavaScript 日曆和一個"Today"快鍵. # DateTimeField # 一個日期時間字段. 相似 DateField 支持一樣的附加選項. # admin 用兩上文本框 <input type="text"> 表示該字段順序(附帶JavaScript shortcuts). # EmailField # 一個帶有檢查 Email 合法性的 CharField,不接受 maxlength 參數. # FileField # 一個文件上傳字段. # # 要求一個必須有的參數: upload_to, 一個用於保存上載文件的本地文件系統路徑. 這個路徑必須包含 strftime formatting, 該格式將被上載文件的 date/time 替換(so that uploaded files don't fill up the given directory). # # admin 用一個``<input type="file">``部件表示該字段保存的數據(一個文件上傳部件) . # # 在一個 model 中使用 FileField 或 ImageField 須要如下步驟: # # 在你的 settings 文件中, 定義一個完整路徑給 MEDIA_ROOT 以便讓 Django在此處保存上傳文件. (出於性能考慮,這些文件並不保存到數據庫.) 定義 MEDIA_URL 做爲該目錄的公共 URL. 要確保該目錄對 WEB 服務器用戶賬號是可寫的. # 在你的 model 中添加 FileField 或 ImageField, 並確保定義了 upload_to 選項,以告訴 Django 使用 MEDIA_ROOT 的哪一個子目錄保存上傳文件. # 你的數據庫中要保存的只是文件的路徑(相對於 MEDIA_ROOT). 出於習慣你必定很想使用 Django 提供的 get_<fieldname>_url 函數.舉例來講,若是你的 ImageField 叫做 mug_shot, 你就能夠在模板中以 {{ object.get_mug_shot_url }} 這樣的方式獲得圖像的絕對路徑. # FilePathField # 可選項目爲某個特定目錄下的文件名. 支持三個特殊的參數, 其中第一個是必須提供的. # # 參數 描述 # path 必需參數. 一個目錄的絕對文件系統路徑. FilePathField 據此獲得可選項目. Example: "/home/images". # match 可選參數. 一個正則表達式, 做爲一個字符串, FilePathField 將使用它過濾文件名. 注意這個正則表達式只會應用到 base filename 而不是路徑全名. Example: "foo.*\.txt^", 將匹配文件 foo23.txt 卻不匹配 bar.txt 或 foo23.gif. # recursive 可選參數.要麼 True 要麼 False. 默認值是 False. 是否包括 path 下面的所有子目錄. # 這三個參數能夠同時使用. # # 我已經告訴過你 match 僅應用於 base filename, 而不是路徑全名. 那麼,這個例子: # # FilePathField(path="/home/images", match="foo.*", recursive=True) # ...會匹配 /home/images/foo.gif 而不匹配 /home/images/foo/bar.gif # FloatField # 一個浮點數. 必須 提供兩個 參數: # # 參數 描述 # max_digits 總位數(不包括小數點和符號) # decimal_places 小數位數 # 舉例來講, 要保存最大值爲 999 (小數點後保存2位),你要這樣定義字段: # # models.FloatField(..., max_digits=5, decimal_places=2) # 要保存最大值一百萬(小數點後保存10位)的話,你要這樣定義: # # models.FloatField(..., max_digits=19, decimal_places=10) # admin 用一個文本框(<input type="text">)表示該字段保存的數據. # ImageField # 相似 FileField, 不過要校驗上傳對象是不是一個合法圖片.它有兩個可選參數:height_field 和 width_field,若是提供這兩個參數,則圖片將按提供的高度和寬度規格保存. # # 該字段要求 Python Imaging Library. # IntegerField # 用於保存一個整數. # # admin 用一個``<input type="text">``表示該字段保存的數據(一個單行編輯框) # IPAddressField # 一個字符串形式的 IP 地址, (i.e. "24.124.1.30"). # # admin 用一個``<input type="text">``表示該字段保存的數據(一個單行編輯框) # NullBooleanField # 相似 BooleanField, 不過容許 NULL 做爲其中一個選項. 推薦使用這個字段而不要用 BooleanField 加 null=True 選項. # # admin 用一個選擇框 <select> (三個可選擇的值: "Unknown", "Yes" 和 "No" ) 來表示這種字段數據. # PhoneNumberField # 一個帶有合法美國風格電話號碼校驗的 CharField``(格式: ``XXX-XXX-XXXX). # PositiveIntegerField # 相似 IntegerField, 但取值範圍爲非負整數(這個字段應該是容許0值的....因此字段名字取得不太好,無符號整數就對了嘛). # PositiveSmallIntegerField # 相似 PositiveIntegerField, 取值範圍較小(數據庫相關) # SlugField # "Slug" 是一個報紙術語. slug 是某個東西的小小標記(短籤), 只包含字母,數字,下劃線和連字符.它們一般用於URLs. # # 若你使用 Django 開發版本,你能夠指定 maxlength. 若 maxlength 未指定, Django 會使用默認長度: 50. 在之前的 Django 版本,沒有任何辦法改變 50 這個長度. # # 這暗示了 db_index=True. # # 它接受一個額外的參數: prepopulate_from, which is a list of fields from which to auto-populate the slug, via JavaScript, in the object's admin form: # # models.SlugField(prepopulate_from=("pre_name", "name")) # prepopulate_from 不接受 DateTimeFields. # # admin 用一個``<input type="text">``表示 SlugField 字段數據(一個單行編輯框) # SmallIntegerField # 相似 IntegerField, 不過只容許某個取值範圍內的整數.(依賴數據庫) # TextField # 一個容量很大的文本字段. # # admin 用一個 <textarea> (文本區域)表示該字段數據.(一個多行編輯框). # TimeField # A time. Accepts the same auto-population options as DateField 和 DateTimeField. # # admin 用一個 <input type="text"> 文本框表示該字段保存的數據(附加一些JavaScript shortcuts). # URLField # 用於保存 URL. 若 verify_exists 參數爲 True (默認), 給定的 URL 會預先檢查是否存在(即URL是否被有效裝入且沒有返回404響應). # # admin 用一個 <input type="text"> 文本框表示該字段保存的數據(一個單行編輯框) # USStateField # 一個兩字母的美國州名縮寫. # # admin 用一個 <input type="text"> 文本框表示該字段保存的數據(一個單行編輯框) # XMLField # 一個校驗值是否爲合法XML的 TextField,必須提供參數: schema_path, 它是一個用來校驗文本的 RelaxNG schema 的文件系統路徑.
4.2.1 模型類的定義(二)
4.2.1 模型類的定義(二)
一 定義數據模型的擴展屬性
經過內部類Meta給數據模型類增長擴展屬性:
class Meta:
verbose_name='名稱' #表名由英文轉換成中文了
verbose_name_plural='名稱複數形式'
ordering='排序字段'
建立超級用戶後,登陸admin發現咱們定義的表並不在,咱們須要對所建立的表(類)進行註冊:
from django.contrib import admin # Register your models here. from app01.models import * admin.site.register(Author) admin.site.register(AuthorDetail) admin.site.register(Publisher) admin.site.register(Book)
這是由於:
二 定義模型方法
定義模型方法和定義普通python類方法沒有太大的差異,定義模型方法能夠將當前對應的數據組裝成具體的業務邏輯。
示例:定義__str__()讓對象有一個名字
def __str__(self): return self.name #py2 def __unicode__(self): return self.name
當添加一個做者保存後:
這裏只顯示生成了一個做者對象,可咱們但願在這裏出現的是做者的名字,因此:
刷新頁面:
4.3 ORM經常使用操做
4.3.1 增長
create和save方法
實例:
Author.objects.create(name='abcd') AuthorDetail.objects.create(sex=False, email='123@qq.com', address='bejing', birthday='1999-9-9',author_id=1) ******************************************** author= Author() author.name = 'eve' author.save()
注意:若是每次建立一個對象,想顯示對應的raw sql,須要在settings加上日誌記錄部分:
LOGGING = { # 'version': 1, # 'disable_existing_loggers': False, # 'handlers': { # 'console':{ # 'level':'DEBUG', # 'class':'logging.StreamHandler', # }, # }, # 'loggers': { # 'django.db.backends': { # 'handlers': ['console'], # 'propagate': True, # 'level':'DEBUG', # }, # } # }
那麼如何插入存在 外鍵 和 多對多關係 的一本書的信息呢?
pub = Publisher.objects.get(id=1) Book.objects.create(title='php', publisher=pub, publication_date='2017-7-7') author1=Author.objects.get(id=1) book=Book.objects.get(id=1) book.authors.add(author1)
總結:
1 objects: model默認管理器。
2 插入主外鍵關係的時候,能夠用對象的方式,也能夠用關聯id的方式。
3 插入多對多關係的時候要分步操做。
4 create是管理器objects的方法
save是model對象的方法
4.3.2 修改
update和save方法
實例:
author = Author.objects.get(id=2) author.name = 'mnm' author.save() Publisher.objects.filter(id=1).update(name='American publisher')
注意:<1> update是QuerySet對象的方法,get返回的是一個model對象,它沒有update方法,而filter返回的是一個QuerySet對象。
<2> save()方法,這個方法會更新一行裏的全部列。
<3> update()方法對於任何結果集(QuerySet)均有效,這意味着你能夠同時更新多條記錄。
<4> update()方法會返回一個整型數值,表示受影響的記錄條數。
Publisher.objects.all().update(country='USA')
4.3.3 查詢
models.Tb1.objects.get(id=123) # 獲取單條數據,不存在則報錯(不建議) models.Tb1.objects.all() # 獲取所有 models.Tb1.objects.filter(name='seven') # 獲取指定條件的數據
4.3.4 刪除
models.Tb1.objects.filter(name='seven').delete() # 刪除指定條件的數據
咱們表面上刪除了一條信息,實際卻刪除了三條,由於咱們刪除的這本書在Book_authors表中有兩條相關信息,這種刪除方式就是django默認的級聯刪除。
1、建立表
一、基本結構
from django.db import models class userinfo(models.Model): name = models.CharField(max_length=30) email = models.EmailField() memo = models.TextField()
AutoField(Field) - int自增列,必須填入參數 primary_key=True BigAutoField(AutoField) - bigint自增列,必須填入參數 primary_key=True 注:當model中若是沒有自增列,則自動會建立一個列名爲id的列 from django.db import models class UserInfo(models.Model): # 自動建立一個列名爲id的且爲自增的整數列 username = models.CharField(max_length=32) class Group(models.Model): # 自定義自增列 nid = models.AutoField(primary_key=True) name = models.CharField(max_length=32) SmallIntegerField(IntegerField): - 小整數 -32768 ~ 32767 PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField) - 正小整數 0 ~ 32767 IntegerField(Field) - 整數列(有符號的) -2147483648 ~ 2147483647 PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField) - 正整數 0 ~ 2147483647 BigIntegerField(IntegerField): - 長整型(有符號的) -9223372036854775808 ~ 9223372036854775807 自定義無符號整數字段 class UnsignedIntegerField(models.IntegerField): def db_type(self, connection): return 'integer UNSIGNED' PS: 返回值爲字段在數據庫中的屬性,Django字段默認的值爲: 'AutoField': 'integer AUTO_INCREMENT', 'BigAutoField': 'bigint AUTO_INCREMENT', 'BinaryField': 'longblob', 'BooleanField': 'bool', 'CharField': 'varchar(%(max_length)s)', 'CommaSeparatedIntegerField': 'varchar(%(max_length)s)', 'DateField': 'date', 'DateTimeField': 'datetime', 'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)', 'DurationField': 'bigint', 'FileField': 'varchar(%(max_length)s)', 'FilePathField': 'varchar(%(max_length)s)', 'FloatField': 'double precision', 'IntegerField': 'integer', 'BigIntegerField': 'bigint', 'IPAddressField': 'char(15)', 'GenericIPAddressField': 'char(39)', 'NullBooleanField': 'bool', 'OneToOneField': 'integer', 'PositiveIntegerField': 'integer UNSIGNED', 'PositiveSmallIntegerField': 'smallint UNSIGNED', 'SlugField': 'varchar(%(max_length)s)', 'SmallIntegerField': 'smallint', 'TextField': 'longtext', 'TimeField': 'time', 'UUIDField': 'char(32)', BooleanField(Field) - 布爾值類型 NullBooleanField(Field): - 能夠爲空的布爾值 CharField(Field) - 字符類型 - 必須提供max_length參數, max_length表示字符長度 TextField(Field) - 文本類型 EmailField(CharField): - 字符串類型,Django Admin以及ModelForm中提供驗證機制 IPAddressField(Field) - 字符串類型,Django Admin以及ModelForm中提供驗證 IPV4 機制 GenericIPAddressField(Field) - 字符串類型,Django Admin以及ModelForm中提供驗證 Ipv4和Ipv6 - 參數: protocol,用於指定Ipv4或Ipv6, 'both',"ipv4","ipv6" unpack_ipv4, 若是指定爲True,則輸入::ffff:192.0.2.1時候,可解析爲192.0.2.1,開啓刺功能,須要protocol="both" URLField(CharField) - 字符串類型,Django Admin以及ModelForm中提供驗證 URL SlugField(CharField) - 字符串類型,Django Admin以及ModelForm中提供驗證支持 字母、數字、下劃線、鏈接符(減號) CommaSeparatedIntegerField(CharField) - 字符串類型,格式必須爲逗號分割的數字 UUIDField(Field) - 字符串類型,Django Admin以及ModelForm中提供對UUID格式的驗證 FilePathField(Field) - 字符串,Django Admin以及ModelForm中提供讀取文件夾下文件的功能 - 參數: path, 文件夾路徑 match=None, 正則匹配 recursive=False, 遞歸下面的文件夾 allow_files=True, 容許文件 allow_folders=False, 容許文件夾 FileField(Field) - 字符串,路徑保存在數據庫,文件上傳到指定目錄 - 參數: upload_to = "" 上傳文件的保存路徑 storage = None 存儲組件,默認django.core.files.storage.FileSystemStorage ImageField(FileField) - 字符串,路徑保存在數據庫,文件上傳到指定目錄 - 參數: upload_to = "" 上傳文件的保存路徑 storage = None 存儲組件,默認django.core.files.storage.FileSystemStorage width_field=None, 上傳圖片的高度保存的數據庫字段名(字符串) height_field=None 上傳圖片的寬度保存的數據庫字段名(字符串) DateTimeField(DateField) - 日期+時間格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ] DateField(DateTimeCheckMixin, Field) - 日期格式 YYYY-MM-DD TimeField(DateTimeCheckMixin, Field) - 時間格式 HH:MM[:ss[.uuuuuu]] DurationField(Field) - 長整數,時間間隔,數據庫中按照bigint存儲,ORM中獲取的值爲datetime.timedelta類型 FloatField(Field) - 浮點型 DecimalField(Field) - 10進制小數 - 參數: max_digits,小數總長度 decimal_places,小數位長度 BinaryField(Field) - 二進制類型 字段
null 數據庫中字段是否能夠爲空 db_column 數據庫中字段的列名 db_tablespace default 數據庫中字段的默認值 primary_key 數據庫中字段是否爲主鍵 db_index 數據庫中字段是否能夠創建索引 unique 數據庫中字段是否能夠創建惟一索引 unique_for_date 數據庫中字段【日期】部分是否能夠創建惟一索引 unique_for_month 數據庫中字段【月】部分是否能夠創建惟一索引 unique_for_year 數據庫中字段【年】部分是否能夠創建惟一索引 verbose_name Admin中顯示的字段名稱 blank Admin中是否容許用戶輸入爲空 editable Admin中是否能夠編輯 help_text Admin中該字段的提示信息 choices Admin中顯示選擇框的內容,用不變更的數據放在內存中從而避免跨表操做 如:gf = models.IntegerField(choices=[(0, '何穗'),(1, '大表姐'),],default=1) error_messages 自定義錯誤信息(字典類型),從而定製想要顯示的錯誤信息; 字典健:null, blank, invalid, invalid_choice, unique, and unique_for_date 如:{'null': "不能爲空.", 'invalid': '格式錯誤'} validators 自定義錯誤驗證(列表類型),從而定製想要的驗證規則 from django.core.validators import RegexValidator from django.core.validators import EmailValidator,URLValidator,DecimalValidator,\ MaxLengthValidator,MinLengthValidator,MaxValueValidator,MinValueValidator 如: test = models.CharField( max_length=32, error_messages={ 'c1': '優先錯信息1', 'c2': '優先錯信息2', 'c3': '優先錯信息3', }, validators=[ RegexValidator(regex='root_\d+', message='錯誤了', code='c1'), RegexValidator(regex='root_112233\d+', message='又錯誤了', code='c2'), EmailValidator(message='又錯誤了', code='c3'), ] )
class UserInfo(models.Model): nid = models.AutoField(primary_key=True) username = models.CharField(max_length=32) class Meta: # 數據庫中生成的表名稱 默認 app名稱 + 下劃線 + 類名 db_table = "table_name" # 聯合索引 index_together = [ ("pub_date", "deadline"), ] # 聯合惟一索引 unique_together = (("driver", "restaurant"),) # admin中顯示的表名稱 verbose_name # verbose_name加s verbose_name_plural 更多:https://docs.djangoproject.com/en/1.10/ref/models/options/
1.觸發Model中的驗證和錯誤提示有兩種方式: a. Django Admin中的錯誤信息會優先根據Admiin內部的ModelForm錯誤信息提示,若是都成功,纔來檢查Model的字段並顯示指定錯誤信息 b. 調用Model對象的 clean_fields 方法,如: # models.py class UserInfo(models.Model): nid = models.AutoField(primary_key=True) username = models.CharField(max_length=32) email = models.EmailField(error_messages={'invalid': '格式錯了.'}) # views.py def index(request): obj = models.UserInfo(username='11234', email='uu') try: print(obj.clean_fields()) except Exception as e: print(e) return HttpResponse('ok') # Model的clean方法是一個鉤子,可用於定製操做,如:上述的異常處理。 2.Admin中修改錯誤提示 # admin.py from django.contrib import admin from model_club import models from django import forms class UserInfoForm(forms.ModelForm): username = forms.CharField(error_messages={'required': '用戶名不能爲空.'}) email = forms.EmailField(error_messages={'invalid': '郵箱格式錯誤.'}) age = forms.IntegerField(initial=1, error_messages={'required': '請輸入數值.', 'invalid': '年齡必須爲數值.'}) class Meta: model = models.UserInfo # fields = ('username',) fields = "__all__" class UserInfoAdmin(admin.ModelAdmin): form = UserInfoForm admin.site.register(models.UserInfo, UserInfoAdmin)
二、連表結構
一對多:models.ForeignKey(其餘表)
多對多:models.ManyToManyField(其餘表)
一對一:models.OneToOneField(其餘表)
ForeignKey(ForeignObject) # ForeignObject(RelatedField) to, # 要進行關聯的表名 to_field=None, # 要關聯的表中的字段名稱 on_delete=None, # 當刪除關聯表中的數據時,當前表與其關聯的行的行爲 - models.CASCADE,刪除關聯數據,與之關聯也刪除 - models.DO_NOTHING,刪除關聯數據,引起錯誤IntegrityError - models.PROTECT,刪除關聯數據,引起錯誤ProtectedError - models.SET_NULL,刪除關聯數據,與之關聯的值設置爲null(前提FK字段須要設置爲可空) - models.SET_DEFAULT,刪除關聯數據,與之關聯的值設置爲默認值(前提FK字段須要設置默認值) - models.SET,刪除關聯數據, a. 與之關聯的值設置爲指定值,設置:models.SET(值) b. 與之關聯的值設置爲可執行對象的返回值,設置:models.SET(可執行對象) def func(): return 10 class MyModel(models.Model): user = models.ForeignKey( to="User", to_field="id" on_delete=models.SET(func),) related_name=None, # 反向操做時,使用的字段名,用於代替 【表名_set】 如: obj.表名_set.all() related_query_name=None, # 反向操做時,使用的鏈接前綴,用於替換【表名】 如: models.UserGroup.objects.filter(表名__字段名=1).values('表名__字段名') limit_choices_to=None, # 在Admin或ModelForm中顯示關聯數據時,提供的條件: # 如: - limit_choices_to={'nid__gt': 5} - limit_choices_to=lambda : {'nid__gt': 5} from django.db.models import Q - limit_choices_to=Q(nid__gt=10) - limit_choices_to=Q(nid=8) | Q(nid__gt=10) - limit_choices_to=lambda : Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root') db_constraint=True # 是否在數據庫中建立外鍵約束 parent_link=False # 在Admin中是否顯示關聯數據 OneToOneField(ForeignKey) to, # 要進行關聯的表名 to_field=None # 要關聯的表中的字段名稱 on_delete=None, # 當刪除關聯表中的數據時,當前表與其關聯的行的行爲 ###### 對於一對一 ###### # 1. 一對一其實就是 一對多 + 惟一索引 # 2.當兩個類之間有繼承關係時,默認會建立一個一對一字段 # 以下會在A表中額外增長一個c_ptr_id列且惟一: class C(models.Model): nid = models.AutoField(primary_key=True) part = models.CharField(max_length=12) class A(C): id = models.AutoField(primary_key=True) code = models.CharField(max_length=1) ManyToManyField(RelatedField) to, # 要進行關聯的表名 related_name=None, # 反向操做時,使用的字段名,用於代替 【表名_set】 如: obj.表名_set.all() related_query_name=None, # 反向操做時,使用的鏈接前綴,用於替換【表名】 如: models.UserGroup.objects.filter(表名__字段名=1).values('表名__字段名') limit_choices_to=None, # 在Admin或ModelForm中顯示關聯數據時,提供的條件: # 如: - limit_choices_to={'nid__gt': 5} - limit_choices_to=lambda : {'nid__gt': 5} from django.db.models import Q - limit_choices_to=Q(nid__gt=10) - limit_choices_to=Q(nid=8) | Q(nid__gt=10) - limit_choices_to=lambda : Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root') symmetrical=None, # 僅用於多對多自關聯時,symmetrical用於指定內部是否建立反向操做的字段 # 作以下操做時,不一樣的symmetrical會有不一樣的可選字段 models.BB.objects.filter(...) # 可選字段有:code, id, m1 class BB(models.Model): code = models.CharField(max_length=12) m1 = models.ManyToManyField('self',symmetrical=True) # 可選字段有: bb, code, id, m1 class BB(models.Model): code = models.CharField(max_length=12) m1 = models.ManyToManyField('self',symmetrical=False) through=None, # 自定義第三張表時,使用字段用於指定關係表 through_fields=None, # 自定義第三張表時,使用字段用於指定關係表中那些字段作多對多關係表 from django.db import models class Person(models.Model): name = models.CharField(max_length=50) class Group(models.Model): name = models.CharField(max_length=128) members = models.ManyToManyField( Person, through='Membership', through_fields=('group', 'person'), ) class Membership(models.Model): group = models.ForeignKey(Group, on_delete=models.CASCADE) person = models.ForeignKey(Person, on_delete=models.CASCADE) inviter = models.ForeignKey( Person, on_delete=models.CASCADE, related_name="membership_invites", ) invite_reason = models.CharField(max_length=64) db_constraint=True, # 是否在數據庫中建立外鍵約束 db_table=None, # 默認建立第三張表時,數據庫中表的名稱
建立表時,順序問題:
class UserType(models.Model): nid = models.AutoField(primary_key=True) caption = models.CharField(max_length=16) class UserInfo(models.Model): name = models.CharField(max_length=32) email = models.EmailField(max_length=32) pwd = models.CharField(max_length=64) user_type = models.ForeignKey(UserType) # UserType已存在時 #********************************************* class UserInfo(models.Model): name = models.CharField(max_length=32) email = models.EmailField(max_length=32) pwd = models.CharField(max_length=64) user_type = models.ForeignKey("UserType") #UserType 不存在時 加上雙引號 class UserType(models.Model): nid = models.AutoField(primary_key=True) caption = models.CharField(max_length=16)
2、操做表
一、基本操做
# 增 # # models.Tb1.objects.create(c1='xx', c2='oo') 增長一條數據,能夠接受字典類型數據 **kwargs # # tb1_dict = {'a1':'123',...} # models.Tb1.objects.create(**tb1_dict) # obj = models.Tb1(c1='xx', c2='oo') # obj.save() # 查 # # models.Tb1.objects.get(id=123) # 獲取單條數據,不存在則報錯(不建議) # models.Tb1.objects.all() # 獲取所有 # models.Tb1.objects.filter(name='seven') # 獲取指定條件的數據 # 刪 # # models.Tb1.objects.filter(name='seven').delete() # 刪除指定條件的數據 # 改 # models.Tb1.objects.filter(name='seven').update(gender='0') # 將指定條件的數據更新,均支持 **kwargs # obj = models.Tb1.objects.get(id=1) # obj.c1 = '111' # obj.save() # 修改單條數據
二、進階操做(了不得的雙下劃線)
利用雙下劃線將字段和對應的操做鏈接起來
# 獲取個數 # # models.Tb1.objects.filter(name='seven').count() # 大於,小於 # # models.Tb1.objects.filter(id__gt=1) # 獲取id大於1的值 # models.Tb1.objects.filter(id__gte=1) # 獲取id大於等於1的值 # models.Tb1.objects.filter(id__lt=10) # 獲取id小於10的值 # models.Tb1.objects.filter(id__lte=10) # 獲取id小於10的值 # models.Tb1.objects.filter(id__lt=10, id__gt=1) # 獲取id大於1 且 小於10的值 # in # # models.Tb1.objects.filter(id__in=[11, 22, 33]) # 獲取id等於十一、2二、33的數據 # models.Tb1.objects.exclude(id__in=[11, 22, 33]) # not in # isnull # Entry.objects.filter(pub_date__isnull=True) # contains # # models.Tb1.objects.filter(name__contains="ven") # models.Tb1.objects.filter(name__icontains="ven") # icontains大小寫不敏感 # models.Tb1.objects.exclude(name__icontains="ven") # range # # models.Tb1.objects.filter(id__range=[1, 2]) # 範圍bettwen and # 其餘相似 # # startswith,istartswith, endswith, iendswith, # order by # # models.Tb1.objects.filter(name='seven').order_by('id') # asc # models.Tb1.objects.filter(name='seven').order_by('-id') # desc # group by # # from django.db.models import Count, Min, Max, Sum # models.Tb1.objects.filter(c1=1).values('id').annotate(c=Count('num')) # SELECT "app01_tb1"."id", COUNT("app01_tb1"."num") AS "c" FROM "app01_tb1" WHERE "app01_tb1"."c1" = 1 GROUP BY "app01_tb1"."id" # limit 、offset # # models.Tb1.objects.all()[10:20] # regex正則匹配,iregex 不區分大小寫 # # Entry.objects.get(title__regex=r'^(An?|The) +') # Entry.objects.get(title__iregex=r'^(an?|the) +') # date # # Entry.objects.filter(pub_date__date=datetime.date(2005, 1, 1)) # Entry.objects.filter(pub_date__date__gt=datetime.date(2005, 1, 1)) # year # # Entry.objects.filter(pub_date__year=2005) # Entry.objects.filter(pub_date__year__gte=2005) # month # # Entry.objects.filter(pub_date__month=12) # Entry.objects.filter(pub_date__month__gte=6) # day # # Entry.objects.filter(pub_date__day=3) # Entry.objects.filter(pub_date__day__gte=3) # week_day # # Entry.objects.filter(pub_date__week_day=2) # Entry.objects.filter(pub_date__week_day__gte=2) # hour # # Event.objects.filter(timestamp__hour=23) # Event.objects.filter(time__hour=5) # Event.objects.filter(timestamp__hour__gte=12) # minute # # Event.objects.filter(timestamp__minute=29) # Event.objects.filter(time__minute=46) # Event.objects.filter(timestamp__minute__gte=29) # second # # Event.objects.filter(timestamp__second=31) # Event.objects.filter(time__second=2) # Event.objects.filter(timestamp__second__gte=31)
一對多,實例使用表結構:
class UserType(models.Model): nid = models.AutoField(primary_key=True) caption = models.CharField(max_length=16) class UserInfo(models.Model): name = models.CharField(max_length=32) email = models.EmailField(max_length=32) pwd = models.CharField(max_length=64) user_type = models.ForeignKey(UserType)
查詢:
ret = models.UserType.objects.all() print(ret,type(ret)) # <QuerySet [<UserType: UserType object>, <UserType: UserType object>, ]> <class 'django.db.models.query.QuerySet'> # [對象,...,...] => 獲得對象列表 for item in ret: print(item,item.nid,item.caption) ret = models.UserType.objects.all().values('nid')# <QuerySet [{'nid': 1}, {'nid': 2}, {'nid': 3}]> # [字典,...,...] ret = models.UserType.objects.all().values_list('nid')# <QuerySet [(1,), (2,), (3,)]> # [元組,...,...]
連表查詢:
ret = models.UserInfo.objects.all() for item in ret: print(item.name,item.user_type.caption) #經過Userinfo表的外鍵user_type去查詢了UserType表 # alex 管理員 # eric 普通用戶 ret = models.UserInfo.objects.all().values('id','user_type__caption') # <QuerySet [{'user_type__caption': '管理員', 'id': 1}, {'user_type__caption': '普通用戶', 'id': 2}]> # 正向查找: ret = models.UserInfo.objects.filter(id=1) ret = models.UserInfo.objects.filter(user_type__caption='管理員') # 返回 [對象,...,...] 列表 # 能夠經過 .來訪問該對象的屬性 ret = models.UserInfo.objects.filter(user_type__caption='管理員').values('name','user_type__caption') # <QuerySet [{'name': 'alex', 'user_type__caption': '管理員'}]> # 返回 [字典,...,...] 列表
反向查找:
ret = models.UserType.objects.filter(caption='管理員').first() print(ret) # UserType object obj = ret.userinfo_set.all() obj = ret.userinfo_set.filter(id=1) # <QuerySet [<UserInfo: UserInfo object>]> for item in obj: print(item.name,item.email) # 方法二: ret = models.UserType.objects.all().values('nid','caption','userinfo__name') # 以UserType表爲主, 鏈接UserInfo表 , 不存在的爲 None # <QuerySet [{'caption': '管理員', 'userinfo__name': 'alex', 'nid': 1}, {'caption': '管理員', 'userinfo__name': 'eric', 'nid': 1}, {'caption': '普通用戶', 'userinfo__name': None, 'nid': 2}, {'caption': '超級管理員', 'userinfo__name': None, 'nid': 3}]> ret = models.UserType.objects.filter(nid=1,userinfo__name='alex') # 返回 UserType對象列表 # <QuerySet [<UserType: UserType object>]>
多對多,實例使用表結構:
class Host(models.Model): hid = models.AutoField(primary_key=True) hostname = models.CharField(max_length=32) ip = models.CharField(max_length=32) #h2g = models.ManyToManyField(Group) class Group(models.Model): gid = models.AutoField(primary_key=True) name = models.CharField(max_length=16) h2g = models.ManyToManyField(Host) # **************************************** # 填充數據: models.Host.objects.create(hostname='alex1',ip='1.1.1.1') models.Host.objects.create(hostname='alex2',ip='1.1.1.2') models.Host.objects.create(hostname='alex3',ip='1.1.1.3') models.Host.objects.create(hostname='alex4',ip='1.1.1.4') models.Host.objects.create(hostname='alex5',ip='1.1.1.5') models.Host.objects.create(hostname='alex6',ip='1.1.1.6') models.Host.objects.create(hostname='alex7',ip='1.1.1.7') models.Group.objects.create(name='運營部') models.Group.objects.create(name='運維部') models.Group.objects.create(name='人事部') models.Group.objects.create(name='開發部') models.Group.objects.create(name='後勤部')
狀況一: 關係表(自動建立)
添加:
# 一個一個添加 h1 = models.Host.objects.get(hid=1) g1 = models.Group.objects.get(gid=1) g1.h2g.add(h1) # 批量添加(多臺機器分給一個組) g1 = models.Group.objects.get(gid=1) h = models.Host.objects.filter(hid__gt=3) g1.h2g.add(*h) # 一臺機器分給多個組 h1 = models.Host.objects.get(hid=5) g = models.Group.objects.filter(gid__gt=3) h1.group_set.add(*g)
能夠發如今 Host表中,隱含了一個 group_set
class Host(models.Model): hid = models.AutoField(primary_key=True) hostname = models.CharField(max_length=32) ip = models.CharField(max_length=32) group_set = .... class Group(models.Model): gid = models.AutoField(primary_key=True) name = models.CharField(max_length=16) h2g = models.ManyToManyField(Host) # 只生成3列
刪除:
h = models.Host.objects.get(hid=1) h.group_set.remove(*models.objects.filter(gid__gt=1)) # 關係表,刪除 hid等於1 , gid 大於1的記錄 h.group_set.all().delete() # 關係表,group數據表的數據也刪除了!!!
修改:
h = models.Host.objects.get(hid=1) h.group_set.set(models.Group.objects.filter(gid=3)) # 關係表中, hid = 1 的全部行, 只剩下 , gid = 3 ,其他刪除! # 符合保留,不符合刪除!. (僅限制在 符合hid=1 的關係表的數據行中!!) h.group_set.get_or_create(name='技術部') h.group_set.update_or_create(name='技術部') # 在group添加新的記錄,而後關係表也添加記錄!
補充:
# 傳對象 group= models.Group.objects.get(gid=1) h1.group_set.add(group) # 傳值 h1.group_set.add(1) h1.group_set.add(*[2,3]) # 能夠直接添加id
狀況二: 關係表(本身建立) 須要本身添加惟一約束!
class HostToGroup(models.Model): hgid = models.AutoField(primary_key=True) host_id = models.ForeignKey("Host") group_id = models.ForeignKey("Group") status = models.IntegerField() class Meta: unique_together = [ ("host_id", "group_id"), ] class Host(models.Model): hid = models.AutoField(primary_key=True) hostname = models.CharField(max_length=32) ip = models.CharField(max_length=32) class Group(models.Model): gid = models.AutoField(primary_key=True) name = models.CharField(max_length=16)
模版的組成:HTML代碼+邏輯控制代碼
模版的渲染:
>>> python manange.py shell (進入該django項目的環境) >>> from django.template import Context, Template >>> t = Template('My name is {{ name }}.') >>> c = Context({'name': 'Stephane'}) >>> t.render(c) 'My name is Stephane.'
邏輯控制代碼:
一、變量
{{ item }}
二、句點號
# 後端數據 : s = 'hello' s1 = [1,2] s2 = { 'user':'eriic' } s3 = time.localtime() s4 = Foo( 'eroiic' , 20 ) # 頁面取值 : {{ obj.1 }} # 索引取值 {{ obj.user }} # 根據字段key取值 {{ obj.year }} # 根據屬性取值 {{ obj.name }} # 取類中字段
三、{% if %} 的使用
不容許同一標籤裏同時出現and和or,不然邏輯容易產生歧義
{% if num >= 100 and 8 %} {% elif num < 100%} <p>num小於100</p> {% else %} <p>num等於100</p> {% endif %}
四、{% for %}的使用
{% for i in obj %}
# obj 爲列表 , i 爲值 {{ forloop.counter }} # 模擬索引 , 從1開始算 {{ forloop.counter0 }} # 模擬索引 , 從0開始算 {{ forloop.revcounter }} # 反序索引 , 從最後開始算 # obj 爲字典 , i 爲key , 或者改成: obj.keys obj.values obj.items 進行循環 {% endfor %}
五、Filter(過濾器)
語法格式: {{obj|filter:param}}
# 1 add : 給變量加上相應的值 # # 2 addslashes : 給變量中的引號前加上斜線 # # 3 capfirst : 首字母大寫 # # 4 cut : 從字符串中移除指定的字符 # # 5 date : 格式化日期字符串 # # 6 default : 若是值是False,就替換成設置的默認值,不然就是用原本的值 # # 7 default_if_none: 若是值是None,就替換成設置的默認值,不然就使用原本的值 #實例: #value1="aBcDe" {{ value1|upper }} #value2=5 {{ value2|add:3 }} #value3='he llo wo r ld' {{ value3|cut:' ' }} #import datetime #value4=datetime.datetime.now() {{ value4|date:'Y-m-d' }} #value5=[] {{ value5|default:'空的' }} # 設置默認值 #value6='<a href="#">跳轉</a>' {{ value6 }} # 字符串形式在頁面顯示 {% autoescape off %} # 渲染成瀏覽器能解析的標籤 {{ value6 }} {% endautoescape %} {{ value6|safe }} # 效果同上 {{ value6|striptags }} #value7='1234' {{ value7|filesizeformat }} # obj 數據的大小 ~kb {{ value7|first }} # 取第一個值 {{ value7|length }} # 獲得長度 {{ value7|slice:":-1" }} # 切片 #value8='http://www.baidu.com/?a=1&b=3' {{ value8|urlencode }} # 進行url編碼 value9='hello I am eriic' {{ value9|truncatechars:'6' }} # 按字符截斷 總顯示3個點, 佔用3個位置! {{ value9|truncatewords:'6' }} # 按單詞截斷
六、{%csrf_token%}:csrf_token標籤 , 放到form 表單裏
七、{% with %}:用更簡單的變量名替代複雜的變量名
{% with total=fhjsaldfhjsdfhlasdfhljsdal %}
{{ total }}
{% endwith %}
八、{% verbatim %}: 禁止變量被渲染
{% verbatim %} {{ hello }} # 頁面直接顯示 {{ hello }} {% endverbatim %}
九、{% load %}: 加載標籤庫
自定義filter和simple_tag:
0、如今setting中installed_apps 添加當前的app項目!
一、app項目下建立templatetags
二、建立任意文件 如 my_tags.py
三、引入類,自定義函數
from django import template from django.utils.safestring import mark_safe register = template.Library() #register的名字是固定的,不可改變 @register.filter def filter_multi(v1,v2): return v1 * v2 @register.simple_tag def simple_tag_multi(v1,v2): return v1 * v2 @register.simple_tag def my_input(id,arg): result = "<input type='text' id='%s' class='%s' />" %(id,arg,) return mark_safe(result)
四、HTML中使用
{% load my_tags %} # 引入外部文件 使用: {% my_add 100 101 %} # simple_tag 能夠傳入多個參數 , 不能用於if語句 {{ obj | my_add:num2 }} # filter 最多兩個參數 , if 語句能夠跟filter
模版繼承:
include 模板標籤 {% include %}
該標籤容許在(模板中)包含其它的模板的內容。
標籤的參數是所要包含的模板名稱,能夠是一個變量,也能夠是用單/雙引號硬編碼的字符串。
每當在多個模板中出現相同的代碼時,就應該考慮是否要使用 {% include %} 來減小重複。
extend(繼承)模板標籤
減小共用頁面區域所引發的重複和冗餘代碼
方法一:解決該問題的傳統作法是使用 服務器端的 includes ,你能夠在 HTML 頁面中使用該指令將一個網頁嵌入到另外一箇中。
方法二:模板繼承就是先構造一個基礎框架模板,然後在其子模板中對它所包含站點公用部分和定義塊進行重載。
#1 -- base.html 存放的是頁面共有的代碼 ! .... {% block content %} # 非共有部分用 block代替 , block名字自定義 ... {% endblock %} #2 -- order.html 只保留非共有部分的代碼 ! {% extend 'base.html' %} # 繼承外部文件 {% block cotent %} # 非共有部分的代碼 ! , 會對base.html中的block進行替換 !! .... {% endblock %} # 沒有對應上的block 會在base中原樣顯示! # 若是須要同時顯示父級的代碼 和本身代碼 能夠嵌套使用 {{ block.super }}
更多見文檔:https://docs.djangoproject.com/en/1.10/ref/templates/language/