WEB框架html
框架,即framework,特指爲解決一個開放性問題而設計的具備必定約束性的支撐結構,使用框架能夠幫你快速開發特定的系統,簡單地說,就是你用別人搭建好的舞臺來作表演。前端
對於全部的Web應用,本質上其實就是一個socket服務端,用戶的瀏覽器其實就是一個socket客戶端。python
最簡單的Web應用就是先把HTML用文件保存好,用一個現成的HTTP服務器軟件,接收用戶請求,從文件中讀取HTML,返回。mysql
若是要動態生成HTML,就須要把上述步驟本身來實現。不過,接受HTTP請求、解析HTTP請求、發送HTTP響應都是苦力活,若是咱們本身來寫這些底層代碼,還沒開始寫動態HTML呢,就得花個把月去讀HTTP規範。jquery
正確的作法是底層代碼由專門的服務器軟件實現,咱們用Python專一於生成HTML文檔。由於咱們不但願接觸到TCP鏈接、HTTP原始請求和響應格式,因此,須要一個統一的接口,讓咱們專心用Python編寫Web業務。git
這個接口就是WSGI:Web Server Gateway Interface。程序員
MTV模式web
Django的MTV模式本質是各組件之間爲了保持鬆耦合關係,Django的MTV分別表明:正則表達式
Model(模型):負責業務對象與數據庫的對象(ORM)sql
Template(模版):負責如何把頁面展現給用戶
View(視圖):負責業務邏輯,並在適當的時候調用Model和Template
此外,Django還有一個url分發器,它的做用是將一個個URL的頁面請求分發給不一樣的view處理,view再調用相應的Model和Template
Django基本命令
1. 建立一個django project
django-admin.py startproject mysite 當前目錄下會生成mysite的工程,目錄結構以下: manage.py ----- Django項目裏面的工具,經過它能夠調用django shell和數據庫等。 settings.py ---- 包含了項目的默認設置,包括數據庫信息,調試標誌以及其餘一些工做的變量。 urls.py ----- 負責把URL模式映射到應用程序。
2. 在mysite目錄下建立應用
python manage.py startapp Myproject
3. 啓動django項目
python manage.py runserver 8080
4. 同步更改數據庫表或字段
python manage.py syncdb 注意:Django 1.7.1 及以上的版本須要用如下命令 python manage.py makemigrations python manage.py migrate
這種方法能夠建立表,當你在models.py中新增了類時,運行它就能夠自動在數據庫中建立表了,不用手動建立。
5. 清空數據庫
python manage.py flush
此命令會詢問是 yes 仍是 no, 選擇 yes 會把數據所有清空掉,只留下空表。
6. 建立超級管理員
python manage.py createsuperuser # 按照提示輸入用戶名和對應的密碼就行了郵箱能夠留空,用戶名和密碼必填 # 修改 用戶密碼能夠用: python manage.py changepassword username
7. Django 項目環境終端
python manage.py shell
這個命令和 直接運行 python 進入 shell 的區別是:你能夠在這個 shell 裏面調用當前項目的 models.py 中的 API,對於操做數據的測試很是方便。
8. Django 項目環境終端
python manage.py dbshell
Django 會自動進入在settings.py中設置的數據庫,若是是 MySQL 或 postgreSQL,會要求輸入數據庫用戶密碼。
在這個終端能夠執行數據庫的SQL語句。若是您對SQL比較熟悉,可能喜歡這種方式。
9. 更多命令
python manage.py
查看全部的命令,忘記子名稱的時候特別有用。
10. static配置
STATIC文件還能夠配置STATICFILES_DIRS,指定額外的靜態文件存儲位置。 # STATIC_URL的含義與MEDIA_URL相似。 # ---------------------------------------------------------------------------- #注意1: #爲了後端的更改不會影響前端的引入,避免形成前端大量修改 STATIC_URL = '/static/' #引用名 STATICFILES_DIRS = ( os.path.join(BASE_DIR,"statics") #實際名 ,即實際文件夾的名字 ) #django對引用名和實際名進行映射,引用時,只能按照引用名來,不能按實際名去找 #<script src="/statics/jquery-3.1.1.js"></script> #------error-----不能直接用,必須用STATIC_URL = '/static/': #<script src="/static/jquery-3.1.1.js"></script> #注意2(statics文件夾寫在不一樣的app下,靜態文件的調用): STATIC_URL = '/static/' STATICFILES_DIRS=( ('hello',os.path.join(BASE_DIR,"app01","statics")) , ) #<script src="/static/hello/jquery-1.8.2.min.js"></script> #注意3: STATIC_URL = '/static/' {% load staticfiles %} # <script src={% static "jquery-1.8.2.min.js" %}></script>
路由配置系統(URLconf)
URL配置(URLconf)就像Django 所支撐網站的目錄。它的本質是URL與要爲該URL調用的視圖函數之間的映射表;你就是以這種方式告訴Django,對於這個URL調用這段代碼,對於那個URL調用那段代碼。
urlpatterns = [
url(正則表達式, views視圖函數,參數,別名),
]
參數說明:
一個正則表達式字符串
一個可調用對象,一般爲一個視圖函數或一個指定視圖函數路徑的字符串
可選的要傳遞給視圖函數的默認參數(字典形式)
一個可選的name參數
1. URLconf的正則字符串參數
a. 簡單配置
from django.conf.urls import url from . import views urlpatterns = [ url(r'^articles/2003/$', views.special_case_2003), url(r'^articles/([0-9]{4})/$', views.year_archive), url(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive), url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail), ] NOTE: 1 一旦匹配成功則再也不繼續 2 若要從URL 中捕獲一個值,只須要在它周圍放置一對圓括號。 3 不須要添加一個前導的反斜槓,由於每一個URL 都有。例如,應該是^articles 而不是 ^/articles。 4 每一個正則表達式前面的'r' 是可選的可是建議加上。 一些請求的例子: /articles/2005/3/ 不匹配任何URL 模式,由於列表中的第三個模式要求月份應該是兩個數字。 /articles/2003/ 將匹配列表中的第一個模式不是第二個,由於模式按順序匹配,第一個會首先測試是否匹配。 /articles/2005/03/ 請求將匹配列表中的第三個模式。Django 將調用函數 views.month_archive(request, '2005', '03')。 #設置項是否開啓URL訪問地址後面不爲/跳轉至帶有/的路徑 APPEND_SLASH=True
b. 有名分組(named group)
上面的示例使用簡單的、沒有命名的正則表達式組(經過圓括號)來捕獲URL 中的值並以位置 參數傳遞給視圖。在更高級的用法中,可使用命名的正則表達式組來捕獲URL 中的值並以關鍵字 參數傳遞給視圖。
在Python 正則表達式中,命名正則表達式組的語法是(?P<name>pattern)
,其中name
是組的名稱,pattern
是要匹配的模式。
下面是以上URLconf 使用命名組的重寫:
from django.conf.urls import url from . import views urlpatterns = [ url(r'^articles/2003/$', views.special_case_2003), url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive), url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.month_archive), url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<day>[0-9]{2})/$', views.article_detail), ] 這個實現與前面的示例徹底相同,只有一個細微的差異:捕獲的值做爲關鍵字參數而不是位置參數傳遞給視圖函數。例如: /articles/2005/03/ 請求將調用views.month_archive(request, year='2005', month='03')函數 /articles/2003/03/03/ 請求將調用函數views.article_detail(request, year='2003', month='03', day='03')。 在實際應用中,這意味你的URLconf 會更加明晰且不容易產生參數順序問題的錯誤 —— 你能夠在你的視圖函數定義中從新安排參數的順序。固然,這些好處是以簡潔爲代價;有些開發人員認爲命名組語法醜陋而繁瑣。
c. URLconf 在什麼上查找
URLconf 在請求的URL 上查找,將它當作一個普通的Python 字符串。不包括GET和POST參數以及域名。
例如,http://www.example.com/myapp/ 請求中,URLconf 將查找myapp/
。
在http://www.example.com/myapp/?page=3 請求中,URLconf 仍將查找myapp/
。
URLconf 不檢查請求的方法。換句話講,全部的請求方法 —— 同一個URL的POST
、GET
、HEAD
等等 —— 都將路由到相同的函數。
d. 捕獲的參數永遠是字符串
每一個捕獲的參數都做爲一個普通的Python 字符串傳遞給視圖,不管正則表達式使用的是什麼匹配方式。例如,下面這行URLconf 中:
url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive), views.year_archive() 的year 參數將是一個字符串
e. 指定視圖參數的默認值
有一個方便的小技巧是指定視圖參數的默認值。 下面是一個URLconf 和視圖的示例:
# URLconf from django.conf.urls import url from . import views urlpatterns = [ url(r'^blog/$', views.page), url(r'^blog/page(?P<num>[0-9]+)/$', views.page), ] # View (in blog/views.py) def page(request, num="1"):
在上面的例子中,兩個URL模式指向同一個視圖views.page
—— 可是第一個模式不會從URL 中捕獲任何值。若是第一個模式匹配,page()
函數將使用num
參數的默認值"1"。若是第二個模式匹配,page()
將使用正則表達式捕獲的num
值。
f. Including other URLconfs
from django.conf.urls import include, url urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^blog/', include('blog.urls')), ]
編寫視圖
一個視圖函數,或者簡短來講叫作視圖,是一個簡單的Python函數,它接受web請求,而且返回web響應。響應能夠是一張網頁的HTML內容,一個重定向,一個404錯誤,一個XML文檔,或者一張圖片. . . 是任何東西均可以。不管視圖自己包含什麼邏輯,都要返回響應。代碼寫在哪裏也無所謂,只要它在你的Python目錄下面。除此以外沒有更多的要求了——能夠說「沒有什麼神奇的地方」。爲了可以把代碼放在某個地方,慣例是把視圖放在叫作views.py的文件中,而後把它放到你的項目或者應用目錄裏。
1. 一個簡單的視圖
下面是一個返回當前日期和時間做爲HTML文檔的視圖:
from django.http import HttpResponse import datetime def current_datetime(request): now = datetime.datetime.now() html = "<html><body>It is now %s.</body></html>" % now return HttpResponse(html)
讓咱們逐行閱讀上面的代碼:
2. 快捷函數
a. render函數
---------------render(request, template_name[, context])
結合一個給定的模板和一個給定的上下文字典,並返回一個渲染後的 HttpResponse 對象。
參數:
request: 用於生成響應的請求對象。
template_name:要使用的模板的完整名稱,可選的參數
context:添加到模板上下文的一個字典。默認是一個空字典。若是字典中的某個值是可調用的,視圖將在渲染模板以前調用它。
content_type:生成的文檔要使用的MIME類型。默認爲DEFAULT_CONTENT_TYPE 設置的值。
status:響應的狀態碼。默認爲200。
b. redirect函數
-----------------------------------url.py url(r"login", views.login), url(r"yuan_back", views.yuan_back), -----------------------------------views.py def login(req): if req.method=="POST": if 1: # return redirect("/yuan_back/") name="yuanhao" return render(req,"my backend.html",locals()) return render(req,"login.html",locals()) def yuan_back(req): name="苑昊" return render(req,"my backend.html",locals()) -----------------------------------login.html <form action="/login/" method="post"> <p>姓名<input type="text" name="username"></p> <p>性別<input type="text" name="sex"></p> <p>郵箱<input type="text" name="email"></p> <p><input type="submit" value="submit"></p> </form> -----------------------------------my backend.html <h1>用戶{{ name }}你好</h1> #總結: render和redirect的區別: # 1 if render的頁面須要模板語言渲染,須要的將數據庫的數據加載到html,那麼全部的這一部分 # 除了寫在yuan_back的視圖函數中,必須還要寫在login中,代碼重複,沒有解耦. # 2 the most important: url沒有跳轉到/yuan_back/,而是還在/login/,因此當刷新後 # 又得從新登陸.
Template
1. 模板系統的介紹
你可能已經注意到咱們在例子視圖中返回文本的方式有點特別。 也就是說,HTML被直接硬編碼在 Python代碼之中。
def current_datetime(request): now = datetime.datetime.now() html = "<html><body>It is now %s.</body></html>" % now return HttpResponse(html)
儘管這種技術便於解釋視圖是如何工做的,但直接將HTML硬編碼到你的視圖裏卻並非一個好主意。 讓咱們來看一下爲何:
對頁面設計進行的任何改變都必須對 Python 代碼進行相應的修改。 站點設計的修改每每比底層 Python 代碼的修改要頻繁得多,所以若是能夠在不進行 Python 代碼修改的狀況下變動設計,那將會方便得多。
Python 代碼編寫和 HTML 設計是兩項不一樣的工做,大多數專業的網站開發環境都將他們分配給不一樣的人員(甚至不一樣部門)來完成。 設計者和HTML/CSS的編碼人員不該該被要求去編輯Python的代碼來完成他們的工做。
程序員編寫 Python代碼和設計人員製做模板兩項工做同時進行的效率是最高的,遠勝於讓一我的等待另外一我的完成對某個既包含 Python又包含 HTML 的文件的編輯工做。
基於這些緣由,將頁面的設計和Python的代碼分離開會更乾淨簡潔更容易維護。 咱們可使用 Django的 模板系統 (Template System)來實現這種模式,這就是本章要具體討論的問題。
python的模板:HTML代碼+邏輯控制代碼
2. 模板支持的語法
a. 變量(使用雙大括號來引用變量)
語法格式: {{var_name}} ----------------------------------Template和Context對象 >>> 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.' # 同一模板,多個上下文,一旦有了模板對象,你就能夠經過它渲染多個context,不管什麼時候咱們均可以 # 像這樣使用同一模板源渲染多個context,只進行 一次模板建立而後屢次調用render()方法渲染會 # 更爲高效: # Low for name in ('John', 'Julie', 'Pat'): t = Template('Hello, {{ name }}') print t.render(Context({'name': name})) # Good t = Template('Hello, {{ name }}') for name in ('John', 'Julie', 'Pat'): print t.render(Context({'name': name}))
b. 深度變量的查找(萬能的句點號)
#最好是用幾個例子來講明一下。 # 首先,句點可用於訪問列表索引,例如: >>> from django.template import Template, Context >>> t = Template('Item 2 is {{ items.2 }}.') >>> c = Context({'items': ['apples', 'bananas', 'carrots']}) >>> t.render(c) 'Item 2 is carrots.' #假設你要向模板傳遞一個 Python 字典。 要經過字典鍵訪問該字典的值,可以使用一個句點: >>> from django.template import Template, Context >>> person = {'name': 'Sally', 'age': '43'} >>> t = Template('{{ person.name }} is {{ person.age }} years old.') >>> c = Context({'person': person}) >>> t.render(c) 'Sally is 43 years old.' #一樣,也能夠經過句點來訪問對象的屬性。 比方說, Python 的 datetime.date 對象有 #year 、 month 和 day 幾個屬性,你一樣能夠在模板中使用句點來訪問這些屬性: >>> from django.template import Template, Context >>> import datetime >>> d = datetime.date(1993, 5, 2) >>> d.year 1993 >>> d.month 5 >>> d.day 2 >>> t = Template('The month is {{ date.month }} and the year is {{ date.year }}.') >>> c = Context({'date': d}) >>> t.render(c) 'The month is 5 and the year is 1993.' # 這個例子使用了一個自定義的類,演示了經過實例變量加一點(dots)來訪問它的屬性,這個方法適 # 用於任意的對象。 >>> from django.template import Template, Context >>> class Person(object): ... def __init__(self, first_name, last_name): ... self.first_name, self.last_name = first_name, last_name >>> t = Template('Hello, {{ person.first_name }} {{ person.last_name }}.') >>> c = Context({'person': Person('John', 'Smith')}) >>> t.render(c) 'Hello, John Smith.' # 點語法也能夠用來引用對象的方法。 例如,每一個 Python 字符串都有 upper() 和 isdigit() # 方法,你在模板中可使用一樣的句點語法來調用它們: >>> from django.template import Template, Context >>> t = Template('{{ var }} -- {{ var.upper }} -- {{ var.isdigit }}') >>> t.render(Context({'var': 'hello'})) 'hello -- HELLO -- False' >>> t.render(Context({'var': '123'})) '123 -- 123 -- True' # 注意這裏調用方法時並* 沒有* 使用圓括號 並且也沒法給該方法傳遞參數;你只能調用不需參數的 # 方法。
c. 標籤(tag)的使用(使用大括號和百分比的組合來表示使用tag)
語法格式: {% tags %} {% if %} 的使用 {% if %}標籤計算一個變量值,若是是「true」,即它存在、不爲空而且不是false的boolean值,系統則會顯示{% if %}和{% endif %}間的全部內容 {% if num >= 100 and 8 %} {% if num > 200 %} <p>num大於200</p> {% else %} <p>num大於100小於200</p> {% endif %} {% elif num < 100%} <p>num小於100</p> {% else %} <p>num等於100</p> {% endif %} {% if %} 標籤接受and,or或者not來測試多個變量值或者否認一個給定的變量 {% if %} 標籤不容許同一標籤裏同時出現and和or,不然邏輯容易產生歧義,例以下面的標籤是不合法的: {% if obj1 and obj2 or obj3 %} {% for %}的使用 {% for %}標籤容許你按順序遍歷一個序列中的各個元素,每次循環模板系統都會渲染{% for %}和{% endfor %}之間的全部內容 <ul> {% for obj in list %} <li>{{ obj.name }}</li> {% endfor %} </ul> #在標籤裏添加reversed來反序循環列表: {% for obj in list reversed %} ... {% endfor %} #{% for %}標籤能夠嵌套: {% for country in countries %} <h1>{{ country.name }}</h1> <ul> {% for city in country.city_list %} <li>{{ city }}</li> {% endfor %} </ul> {% endfor %} #系統不支持中斷循環,系統也不支持continue語句,{% for %}標籤內置了一個forloop模板變量, #這個變量含有一些屬性能夠提供給你一些關於循環的信息 1,forloop.counter表示循環的次數,它從1開始計數,第一次循環設爲1: {% for item in todo_list %} <p>{{ forloop.counter }}: {{ item }}</p> {% endfor %} 2,forloop.counter0 相似於forloop.counter,但它是從0開始計數,第一次循環設爲0 3,forloop.revcounter 4,forloop.revcounter0 5,forloop.first當第一次循環時值爲True,在特別狀況下頗有用: {% for object in objects %} {% if forloop.first %}<li class="first">{% else %}<li>{% endif %} {{ object }} </li> {% endfor %} # 富有魔力的forloop變量只能在循環中獲得,當模板解析器到達{% endfor %}時forloop就消失了 # 若是你的模板context已經包含一個叫forloop的變量,Django會用{% for %}標籤替代它 # Django會在for標籤的塊中覆蓋你定義的forloop變量的值 # 在其餘非循環的地方,你的forloop變量仍然可用 #{% empty %} {{li }} {% for i in li %} <li>{{ forloop.counter0 }}----{{ i }}</li> {% empty %} <li>this is empty!</li> {% endfor %} # [11, 22, 33, 44, 55] # 0----11 # 1----22 # 2----33 # 3----44 # 4----55
csrf_token標籤 用於生成csrf_token的標籤,用於防治跨站攻擊驗證。 其實,這裏是會生成一個input標籤,和其餘表單標籤一塊兒提交給後臺的。 {% url %} 引用路由配置的地址 <form action="{% url "bieming"%}" > <input type="text"> <input type="submit"value="提交"> {%csrf_token%} </form> {% with %} 用更簡單的變量名替代複雜的變量名 {% with total=fhjsaldfhjsdfhlasdfhljsdal %} {{ total }} {% endwith %} {% verbatim %} 禁止render {% verbatim %} {{ hello }} {% endverbatim %} {% load %} 略 加載標籤庫:自定義filter和simple_tag a、在app中建立templatetags模塊(必須的) b、建立任意 .py 文件,如:my_tags.py c、在使用自定義simple_tag和filter的html文件中導入以前建立的 my_tags.py :{% load my_tags %} d、使用simple_tag和filter(如何調用) e、在settings中的INSTALLED_APPS配置當前app,否則django沒法找到自定義的simple_tag. 注意: filter能夠用在if等語句後,simple_tag不能夠 {% if num|filter_multi:30 > 100 %} {{ num|filter_multi:30 }} {% endif %}
數據庫與ORM
1. 數據庫配置
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驅動程序)
2. ORM表模型
實例:咱們來假定下面這些概念,字段和關係
做者模型:一個做者有姓名。
做者詳細模型:把做者的詳情放到詳情表,包含性別,email地址和出生日期,做者詳情模型和做者模型之間是一對一的關係(one-to-one)(相似於每一個人和他的身份證之間的關係),在大多數狀況下咱們沒有必要將他們拆分紅兩張表,這裏只是引出一對一的概念。
出版商模型:出版商有名稱,地址,所在城市,省,國家和網站。
書籍模型:書籍有書名和出版日期,一本書可能會有多個做者,一個做者也能夠寫多本書,因此做者和書籍的關係就是多對多的關聯關係(many-to-many),一本書只應該由一個出版商出版,因此出版商和書籍是一對多關聯關係(one-to-many),也被稱做外鍵。
from django.db import models<br> 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
3. ORM之增(create,save)
from app01.models import * #create方式一: Author.objects.create(name='Alvin') #create方式二: Author.objects.create(**{"name":"alex"}) #save方式一: author=Author(name="alvin") author.save() #save方式二: author=Author() author.name="alvin" author.save()
4. ORM之刪(delete)
>>> Book.objects.filter(id=1).delete() (3, {'app01.Book_authors': 2, 'app01.Book': 1})
咱們表面上刪除了一條信息,實際卻刪除了三條,由於咱們刪除的這本書在Book_authors表中有兩條相關信息,這種刪除方式就是django默認的級聯刪除。
5. ORM之改(update和save)
#---------------- update方法直接設定對應屬性---------------- models.Book.objects.filter(id=3).update(title="PHP") ##sql: ##UPDATE "app01_book" SET "title" = 'PHP' WHERE "app01_book"."id" = 3; args=('PHP', 3) #--------------- save方法會將全部屬性從新設定一遍,效率低----------- obj=models.Book.objects.filter(id=3)[0] obj.title="Python" obj.save() # SELECT "app01_book"."id", "app01_book"."title", "app01_book"."price", # "app01_book"."color", "app01_book"."page_num", # "app01_book"."publisher_id" FROM "app01_book" WHERE "app01_book"."id" = 3 LIMIT 1; # # UPDATE "app01_book" SET "title" = 'Python', "price" = 3333, "color" = 'red', "page_num" = 556, # "publisher_id" = 1 WHERE "app01_book"."id" = 3;
6. ORM之查(filter,value)
a. 查詢API
b. QuerySet與惰性機制
c. 對象查詢,單表條件查詢,多表條件關聯查詢
d. 聚合查詢和分組查詢
e. F查詢和Q查詢