前言: 各位久等了,django進階篇來了。html
接口規範: url不能寫動詞,只能寫名詞前端
django默認只支持兩種方式: get, postpython
get是獲取數據mysql
?user=zcl&password=abc&email=669@qq
?號表示後面是參數,&在兩參數中間程序員
request.GET.get("password")
上面這句代碼可獲取密碼abc,是明文的!!web
post獲取密碼是密文的。post請求用於建立或修改數據。sql
if request.method == 'GET':
# <view logic>
return HttpResponse('result')
你可能已經注意到咱們在例子視圖中返回文本的方式有點特別。 也就是說,HTML被直接硬編碼在 Python 代碼之中。shell
1 def current_datetime(request): 2 now = datetime.datetime.now() 3 html = "<html><body>It is now %s.</body></html>" % now 4 return HttpResponse(html)
儘管這種技術便於解釋視圖是如何工做的,但直接將HTML硬編碼到你的視圖裏卻並非一個好主意。 讓咱們來看一下爲何:數據庫
基於這些緣由,將頁面的設計和Python的代碼分離開會更乾淨簡潔更容易維護。 咱們可使用 Django的 模板系統 (Template System)來實現這種模式。django
1 >>> from django.template import Context, Template 2 >>> t = Template('My name is {{ name }}.') 3 >>> c = Context({'name': 'Stephane'}) 4 >>> t.render(c) 5 u'My name is Stephane.'
同一模板,多個上下文: 一旦有了 模板 對象,你就能夠經過它渲染多個context
1 >>> from django.template import Template, Context 2 >>> t = Template('Hello, {{ name }}') 3 >>> print t.render(Context({'name': 'John'})) 4 Hello, John 5 >>> print t.render(Context({'name': 'Julie'})) 6 Hello, Julie 7 >>> print t.render(Context({'name': 'Pat'})) 8 Hello, Pat
不管什麼時候咱們均可以像這樣使用同一模板源渲染多個context,只進行 一次模板建立而後屢次調用render()方法渲染(render)會更爲高效:
1 # Bad
2 for name in ('John', 'Julie', 'Pat'): 3 t = Template('Hello, {{ name }}') 4 print t.render(Context({'name': name})) 5 6 # Good 生成模版實例是有系統開銷的,一個模版實例是能夠進行屢次上下文的渲染
7 t = Template('Hello, {{ name }}') 8 for name in ('John', 'Julie', 'Pat'): 9 print t.render(Context({'name': name}))
注意: 若是沒有python manage.py shell 是會曝錯的!!這句代碼的意義是導入django環境。
在到目前爲止的例子中,咱們經過 context 傳遞的簡單參數值主要是字符串,然而,模板系統可以很是簡潔地處理更加複雜的數據結構,例如list、dictionary和自定義的對象。
在 Django 模板中遍歷複雜數據結構的關鍵是句點字符 (.)。
向模板傳遞一個 Python 字典。 要經過字典鍵訪問該字典的值,可以使用一個句點:
1 >>> from django.template import Template, Context 2 >>> person = {'name': 'Sally', 'age': '43'} 3 >>> t = Template('{{ person.name }} is {{ person.age }} years old.') 4 >>> c = Context({'person': person}) 5 >>> t.render(c) 6 u'Sally is 43 years old.'
一樣,也能夠經過句點來訪問對象的屬性。 比方說, Python 的 datetime.date 對象有 year 、 month 和 day 幾個屬性,你一樣能夠在模板中使用句點來訪問這些屬性:
1 >>> from django.template import Template, Context 2 >>> import datetime 3 >>> d = datetime.date(1993, 5, 2) 4 >>> d.year 5 1993
6 >>> d.month 7 5
8 >>> d.day 9 2
10 >>> t = Template('The month is {{ date.month }} and the year is {{ date.year }}.') 11 >>> c = Context({'date': d}) 12 >>> t.render(c) 13 u'The month is 5 and the year is 1993.'
句點也可用於訪問列表索引,例如:
1 >>> from django.template import Template, Context 2 >>> t = Template('Item 2 is {{ items.2 }}.') 3 >>> c = Context({'items': ['apples', 'bananas', 'carrots']}) 4 >>> t.render(c) 5 u'Item 2 is carrots.'
效果圖(太牛啦):
輸入url經過路由調用index方法:
1 def index(request): 2 if request.method == "GET": 3 user_info = [{"username":"zcl_1","name":"zhang CL",}, 4 {"username": "zcl_2", "name": "zhang CL", }, 5 {"username": "zcl_3", "name": "zhang CL", }, 6 {"username": "zcl_4", "name": "zhang CL", }, 7 {"username": "zcl_5", "name": "zhang CL", },] 8
9 return render(request, "app01/index.html", {"user_objs":user_info})
app01/index.html下部分代碼:
1 <ul>
2 {% for user_obj in user_objs %} 3 {# {% if forloop.counter0 > 2 %}#} 4 {% if forloop.counter0|divisibleby:"2" %} 5 <li style="background-color: darksalmon">username:{{ user_obj.username }};name:{{ user_obj.name }}</li>
6 {% else %} 7 <li style="">username:{{ user_obj.username }};name:{{ user_obj.name }}</li>
8 {% endif %} 9 {% endfor %} 10 </ul>
注意: forloop.counter0表示循環從0開始,divisibleby:"2"表示能被2整除的。PS: 千萬不要寫成divisibleby: "2"(中間加個空格,會曝錯的!!當時我就加了空格,出錯時一臉懵比...)
Templates/app01/page1.html文件:
1 <body>
2 {% extends "app01/index.html" %} {#繼承父模版#} 3 <h1>page1</h1>
4 </body>
5
6 Templates/app01/index.html文件: 7 <body>
8 <ul>
9 <li style="display: inline">Home</li>
10 <li style="display: inline">page1</li>
11 <li style="display: inline">page2</li>
12 <li style="display: inline">page3</li>
13 </ul>
14 <h1>welcome to payment index</h1>
15
16 <footer>
17 <h1>foot</h1>
18 </footer>
19 </body>
Templates/app01/index.html文件:
1 <body> 2 <ul> 3 <li style="display: inline">Home</li> 4 <li style="display: inline">page1</li> 5 <li style="display: inline">page2</li> 6 <li style="display: inline">page3</li> 7 </ul> 8 <h1>welcome to payment index</h1> 9 10 <footer> 11 <h1>foot</h1> 12 </footer> 13 </body>
渲染page1.html文件效果圖:
問題: 發現雖然能夠繼承父模版index.html,可是子模版page1.html的內容被覆蓋。默認所有繼承父模版!!
如何解決這個問題呢? 實際需求上,好比一個網站的上方菜單欄,前端界面基本是同樣的,不一樣頁面會有微小的不一樣。這時我想,我能夠作一個網站的菜單欄做爲父模版,該父模版能夠被其它頁面繼承(extends)或複用(include).
如今我有個需求,我只想替換父模版index.html的 welcome to payment index:
Templates/app01/index.html文件:用block將須要被替換的內容包含起來。
{% block content-container %} <h1>welcome to payment index</h1> {% endblock %}
Templates/app01/page1.html文件: 用block將要替換父模版的內容包含起來。
<body> {% extends "app01/index.html" %} {% block content-container %} {# 重寫父模版的content-container部分 #} <h1>page1</h1> {% endblock %} </body>
繼承效果圖:
複用就簡單了,重複地使用嘛,好比我在register.html寫一個註冊的表單,只要網站的頁面有須要註冊,直接複用以前寫的表單就OK了
{% include "app01/register.html" %}
Templates/app01/page1.html文件:
1 <body> 2 {% extends "app01/index.html" %} 3 {% block content-container %} 4 <h1>page1</h1> 5 {% include "app01/register.html" %} 6 {% endblock %} 7 </body>
Templates/app01/register.html:
<body> <div style="background-color: antiquewhite"> <form> Username:<input name="username" type="text"> Password:<input name="password" type="password"> </form> </div> </body>
繼承+複用效果圖(圖中form表單是複用來的~):
django 自己提供了很是強大易使用的ORM組件,而且支持多種數據庫,如sqllite,mysql,progressSql,Oracle等,固然最經常使用的搭配仍是mysql,要啓用orm,先要配置好鏈接數據 的信息。
爲了更好的理解,咱們來作一個基本的 書籍/做者/出版商 數據庫結構。 咱們這樣作是由於 這是一個衆所周知的例子,不少SQL有關的書籍也經常使用這個舉例。
咱們來假定下面的這些概念、字段和關係:
一個做者有姓,有名及email地址。
出版商有名稱,地址,所在城市、省,國家,網站。
書籍有書名和出版日期。 它有一個或多個做者(書和做者是多對多的關聯關係[many-to-many]), 只有一個出版商(書和出版商是一對多的關聯關係[one-to-many],也被稱做外鍵[foreign key])
第一步:在配置文件加入app名(我建立的app名爲app01)
第二步: 我mysqldb裝不上,爲了方便用默認的sqllite數據庫~
用默認的sqlite數據庫,就啥都不用改,直接看第三步;固然若是你mysqldb模塊裝上了,能夠用mysql數據庫試試,可在settings.py改下數據庫鏈接的配置:
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'OldboyWebsite', #確保此數據庫已存在 'HOST':'', 'PORT':'', 'USER':'root', 'PASSWORD':'' } }
第三步: 建立表結構
1 from django.db import models 2
3 # Create your models here.
4 class Author(models.Model): 5 first_name = models.CharField(max_length=32) 6 last_name = models.CharField(max_length=32) 7 email = models.EmailField() 8
9 def __str__(self): 10 return "<%s %s>" % (self.first_name,self.last_name) 11
12 class Meta: 13 verbose_name_plural = u"做者"
14
15 class Publisher(models.Model): 16 name = models.CharField(max_length=64, unique=True) 17 address = models.CharField(max_length=128,null=True,blank=True) 18 city = models.CharField(max_length=64) 19 state_province = models.CharField(max_length=64,help_text="put your province here",verbose_name=u"所屬省") 20 country = models.CharField(max_length=64,editable=False) 21 website = models.URLField() 22
23 def __str__(self): 24 return "<%s>" % (self.name) 25
26 class Book(models.Model): 27 name = models.CharField(max_length=128) 28 authors = models.ManyToManyField(Author) #書多對多到做者
29 publisher = models.ForeignKey(Publisher) #一對多
30 publish_date = models.DateField() #精確到天DateField()
31
32 def __str__(self): 33 return "<%s %s>" % (self.name,self.publisher)
看上面的代碼,若是你看過我以前的博客sqlalchemy orm和堡壘機表結構設計,就會發現django orm進行多對多關聯時不用本身來生成中間表,天吶!!這可方便了!!
你可能看不懂上面的help_text,verbose_name,editable,class Meta:,def __str__(self):.....這些我等下講,慢慢來,一會兒就高潮就很差了哈哈。
第四步: 爲了能在django後臺的管理員能查看到生成的表,在app01/admin.py文件添加下面代碼:
第五步: 同步數據庫
第六步: 建立superuser
第七步: 登錄admin並建立數據
注意: 在建立表結構時,若是不在表對象中加入def __str__(self):方法(python3下),則會出現下面狀況:沒法顯示出書的名稱。 Python2對應爲def __unicode__(self):
模型字段我這裏講幾個意思意思就行了,更多的請參考官方文檔。
更多models field 字段:https://docs.djangoproject.com/en/1.9/ref/models/fields/
1. null & blank
address = models.CharField(max_length=128,null=True)
在出版社表的address字段加上null = True; 此時address在admin後臺仍不能爲空!
必須再加上bland = True; 限制django admin可爲空。
六級沒過的我,差15分……來看段官方英文熱熱身……只要你看得懂,會發現英文真TM易懂,由於英文不會有歧義。
2. editable = False 表示不能更改
我大天朝的國籍企是你想改就能改的……
country = models.CharField(max_length=64,editable=False)
3. help_text = "xx" 提示文字 不是對數據庫的修改,是對django admin頁面的修改,因此當你增長這個字段,你是不用去同步數據庫的。
state_province = models.CharField(max_length=64,help_text="put your province here")
4. verbose_name 詳細的名字
state_province = models.CharField(max_length=64,help_text="put your province here",verbose_name=u"所屬省")
5. class Meta: 若是想本身在django後臺定義表名,可在表結構加上下面的代碼:
class Meta: verbose_name_plural = u"做者"
上圖!!
查找類型有:icontains(大小寫不敏感的LIKE),startswith和endswith, 還有range
關於修改,有個點要注意下:
在「插入和更新數據」小節中,咱們有提到模型的save()方法,這個方法會更新一行裏的全部列。 而某些狀況下,咱們只須要更新行裏的某幾列。
例如說咱們如今想要將Apress Publisher的名稱由原來的」Apress」更改成」Apress Publishing」。若使用save()方法,如:
>>> p = Publisher.objects.get(name='Apress') >>> p.name = 'Apress Publishing' >>> p.save()
這等同於以下SQL語句:
SELECT id, name, address, city, state_province, country, website FROM books_publisher WHERE name = 'Apress'; UPDATE books_publisher SET name = 'Apress Publishing', address = '2855 Telegraph Ave.', city = 'Berkeley', state_province = 'CA', country = 'U.S.A.', website = 'http://www.apress.com' WHERE id = 52;
(注意在這裏咱們假設Apress的ID爲52)
在這個例子裏咱們能夠看到Django的save()方法更新了不只僅是name列的值,還有更新了全部的列。 若name之外的列有可能會被其餘的進程所改動的狀況下,只更改name列顯然是更加明智的。 更改某一指定的列,咱們能夠調用結果集(QuerySet)對象的update()方法: 示例以下:
>>> Publisher.objects.filter(id=52).update(name='Apress Publishing')
與之等同的SQL語句變得更高效,而且不會引發競態條件。
UPDATE books_publisher SET name = 'Apress Publishing' WHERE id = 52;
update()方法對於任何結果集(QuerySet)均有效,這意味着你能夠同時更新多條記錄。 如下示例演示如何將全部Publisher的country字段值由’U.S.A’更改成’USA’:
>>> Publisher.objects.all().update(country='USA') 2
咱們已經知道如何對數據進行過濾和排序。 固然,一般咱們須要同時進行過濾和排序查詢的操做。 所以,你能夠簡單地寫成這種「鏈式」的形式:
>>> Publisher.objects.filter(country="U.S.A.").order_by("-name") [<Publisher: O'Reilly>, <Publisher: Apress>]
你應該沒猜錯,轉換成SQL查詢就是 WHERE 和 ORDER BY 的組合:
SELECT id, name, address, city, state_province, country, website FROM books_publisher WHERE country = 'U.S.A' ORDER BY name DESC;
如今你找到了一本書的對象b1, 書與做者已經進行多對多關聯,此時你想知道書的做者是誰?
刪除b1這本書,看下圖,刪除b1時會把書與做者中間表對應內容也刪除,真牛!!
參考博客: http://www.cnblogs.com/alex3714/articles/5457672.html 大王這篇博客寫得太亂了……
寫很久,脖子酸