《Web接口開發與自動化測試基於Python語言》–讀書筆記
第4章 Django模型
忽然意識到個嚴重問題,我這樣詳細的筆記,貌似有抄書的嫌疑,這樣大家都不買書了,怕被告盜版,所以從後續章節開始,我只記錄比較重要的知識點,不再做詳細的抄書了,大家如果在閱讀的時候有疑問可以向蟲師請教,或留言給我,我們一起研究。
4.1 設計系統表
模型的基礎知識:
-
每個模型是一個Python類,繼承django.db.models.Model類
-
該模型的每個屬性表示一個數據庫表字段
-
所有這一切,已經給了你一個自動生成數據庫訪問的API
本例所需的模型,修改/guest/sign/models.py文件:
<span style="color:#000000"><code class="language-python"><span style="color:#880000">#! /usr/bin python</span>
<span style="color:#880000"># -*- coding:utf-8 -*-</span>
<span style="color:#000088">from</span> __future__ <span style="color:#000088">import</span> unicode_literals
<span style="color:#000088">from</span> django.db <span style="color:#000088">import</span> models
<span style="color:#880000"># Create your models here.</span>
<span style="color:#880000"># 發佈會表</span>
<span style="color:#000088">class</span> <span style="color:#4f4f4f">Event</span><span style="color:#4f4f4f">(models.Model)</span>:
name = models.CharField(max_length=<span style="color:#006666">100</span>) <span style="color:#880000"># 發佈會標題</span>
limit = models.IntegerField() <span style="color:#880000"># 參加人數</span>
status = models.BooleanField() <span style="color:#880000"># 狀態</span>
address = models.CharField(max_length=<span style="color:#006666">200</span>) <span style="color:#880000"># 地址</span>
start_time = models.DateTimeField(<span style="color:#009900">'events time'</span>) <span style="color:#880000"># 發佈會時間</span>
create_time = models.DateTimeField(auto_now=<span style="color:#000088">True</span>) <span style="color:#880000"># 創建時間(自動獲取當前時間)</span>
<span style="color:#000088">def</span> <span style="color:#009900">__str__</span><span style="color:#4f4f4f">(self)</span>:
<span style="color:#000088">return</span> self.name
<span style="color:#880000"># 嘉賓表</span>
<span style="color:#000088">class</span> <span style="color:#4f4f4f">Guest</span><span style="color:#4f4f4f">(models.Model)</span>:
event = models.ForeignKey(Event) <span style="color:#880000"># 外鍵,關聯發佈會id</span>
realname = models.CharField(max_length=<span style="color:#006666">64</span>) <span style="color:#880000"># 姓名</span>
phone = models.CharField(max_length=<span style="color:#006666">16</span>) <span style="color:#880000"># 電話</span>
email = models.EmailField() <span style="color:#880000"># 郵箱</span>
sign = models.BooleanField() <span style="color:#880000"># 簽到狀態</span>
create_time = models.DateTimeField(auto_now=<span style="color:#000088">True</span>) <span style="color:#880000"># 創建時間(自動獲取當前時間)</span>
<span style="color:#000088">class</span> <span style="color:#4f4f4f">Meta</span>:
unique_together = (<span style="color:#009900">"event"</span>, <span style="color:#009900">"phone"</span>)
<span style="color:#000088">def</span> <span style="color:#009900">__str__</span><span style="color:#4f4f4f">(self)</span>:
<span style="color:#000088">return</span> self.name</code></span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
注意:
-
Model會爲每個表自動生成自增id字段無需聲明;
-
嘉賓表通過event字段關聯發佈會表id字段,一條嘉賓信息對應某一場發佈會;
-
通過發佈會表id+嘉賓表phone作爲聯合主鍵,unique_together用於設置兩個字段爲聯合主鍵;
-
python3使用__str__()方法、python2使用__unicode__()方法,顯示對應字段。
Django模型字段常用類型
類型 | 說明 |
---|---|
AutoField | 一個IntegerField類型的自動增量 |
BooleanField | 用於存放布爾類型的數據(True or False) |
CharField | 用於存放字符型的數據,需要指定長度max_length |
DateField | 用於存放日期類型的數據,格式爲:YYYY-MM-DD |
DecimalField | 用於存放小數型的數據 |
EmailField | 用於存放電子郵件類型的數據 |
FilePathField | 用於存放文件路徑類型的數據 |
FloatField | 用於存放浮點型的數據 |
IntegerField | 用於存放整數類型的數據,範圍是:-2147483648至2147483647 |
BigIntegerField | 用於存放大整數類型的數據,最大支持:9223372036854775807 |
GenericIPAdressField | 用於存放IP地址類型的數據,同時支持IPv4、IPv6,字符串格式 |
NullBooleanField | 類似BooleanField,但是允許填寫NULL |
PositiveIntegerField | 用於存放正數或0的整數類型的數據,範圍是:0-2147483647 |
PositiveSmallIntegerField | 類似PositiveIntegerField,但是範圍是:0-32767 |
SlugField | Slug是短標籤,只包含字母、數字、下劃線或字符,它通常在網址中使用,需要定義max_length |
SmallIntegerField | 類似IntegerField,但是範圍是:-32768至32767 |
TextField | 用於存放文本類型的數據 |
TimeField | 用於存放時間類型的數據,格式爲:HH:MM[:ss[.uuuuuu]] |
URLField | 用於存放URL地址 |
BinaryField | 用於存放原始二進制類型的數據 |
詳細內容可參考官方文檔:
https://docs.djangoproject.com/en/1.10/ref/models/fields/
使用如下命令進行數據庫表的初始化和創建:
python manage.py makemigrations sign
python manage.py migrate
4.2 admin後臺管理
將上面創建的發佈會表、嘉賓表,也加入到admin後臺進行圖形化的管理:
修改/guest/sign/admin.py文件:
<span style="color:#000000"><code class="language-python"><span style="color:#000088">from</span> django.contrib <span style="color:#000088">import</span> admin
<span style="color:#000088">from</span> sign.models <span style="color:#000088">import</span> Event, Guest
<span style="color:#880000"># Register your models here.</span>
admin.site.register(Event)
admin.site.register(Guest)</code></span>
- 1
- 2
- 3
- 4
- 5
- 6
通過管理頁面隨意增加一條發佈會記錄,我這裏在增加一條中文記錄的時候,出現了編碼錯誤的提示:
UnicodeEncodeError at /admin/sign/event/add/
看這意思是中文編碼問題,印象當中之前看Django官方文檔的時候,有關於中文編碼的問題,於是翻了下之前的筆記,發現是修改/guest/settings.py裏的MIDDLEWARE配置,增加一條:
django.middleware.locale.LocaleMiddleware
但是這裏將Django的admin管理後臺的展示從英文變成了本地語言中文,對於上面遇到的錯誤還是沒有幫助,哎,不應該呀,蟲師都能在書中增加一條中文記錄,沒理由我這裏完全按照蟲師講解的一步一步操作過來的會遇到錯誤啊,仔細回頭查看models.py發現了一個小問題,蟲師在書中也提到了只是自己當時忽略了,蟲師使用的是python3,而我使用的是python2,在展示列表的函數裏,蟲師使用的是__str__,而我完全照搬書中的代碼,也使用了__str__,這裏就出錯了,如果是python2,應該使用__unicode__纔對,修改代碼:
<span style="color:#000000"><code class="language-python"><span style="color:#880000"># 發佈會表</span>
<span style="color:#000088">class</span> <span style="color:#4f4f4f">Event</span><span style="color:#4f4f4f">(models.Model)</span>:
name = models.CharField(max_length=<span style="color:#006666">100</span>) <span style="color:#880000"># 發佈會標題</span>
limit = models.IntegerField() <span style="color:#880000"># 參加人數</span>
status = models.BooleanField() <span style="color:#880000"># 狀態</span>
address = models.CharField(max_length=<span style="color:#006666">200</span>) <span style="color:#880000"># 地址</span>
start_time = models.DateTimeField(<span style="color:#009900">'events time'</span>) <span style="color:#880000"># 發佈會時間</span>
create_time = models.DateTimeField(auto_now=<span style="color:#000088">True</span>) <span style="color:#880000"># 創建時間(自動獲取當前時間)</span>
<span style="color:#880000">#def __str__(self):</span>
<span style="color:#000088">def</span> <span style="color:#009900">__unicode__</span><span style="color:#4f4f4f">(self)</span>:
<span style="color:#000088">return</span> self.name</code></span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
再次添加中文記錄,成功,問題解決,後續對於不同版本使用的不同函數,還是要注意啊!
在管理後臺列表中顯示更多字段:
修改/guest/sign/admin.py文件:
<span style="color:#000000"><code class="language-python"><span style="color:#880000">#! /usr/bin python</span>
<span style="color:#880000"># -*- coding:utf-8 -*-</span>
<span style="color:#000088">from</span> django.contrib <span style="color:#000088">import</span> admin
<span style="color:#000088">from</span> sign.models <span style="color:#000088">import</span> Event, Guest
<span style="color:#880000"># Register your models here.</span>
<span style="color:#880000"># 在admin管理後臺展示更多字段</span>
<span style="color:#000088">class</span> <span style="color:#4f4f4f">EventAdmin</span><span style="color:#4f4f4f">(admin.ModelAdmin)</span>:
list_display = [<span style="color:#009900">'id'</span>, <span style="color:#009900">'name'</span>, <span style="color:#009900">'status'</span>, <span style="color:#009900">'address'</span>, <span style="color:#009900">'start_time'</span>]
<span style="color:#000088">class</span> <span style="color:#4f4f4f">GuestAdmin</span><span style="color:#4f4f4f">(admin.ModelAdmin)</span>:
list_display = [<span style="color:#009900">'realname'</span>, <span style="color:#009900">'phone'</span>, <span style="color:#009900">'email'</span>, <span style="color:#009900">'sign'</span>, <span style="color:#009900">'create_time'</span>, <span style="color:#009900">'event'</span>]
<span style="color:#880000"># 在admin管理後臺註冊發佈會表、嘉賓表</span>
admin.site.register(Event, EventAdmin)
admin.site.register(Guest, GuestAdmin)</code></span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
注意:
-
EventAdmin繼承admin.ModelAdmin類,其中ModelAdmin提供了很多自定義管理工具;
-
list_display數組內是顯示的字段名,必須存在於數據表中。
在管理後臺增加搜索欄、過濾器:
還是修改/guest/sign/admin.py文件:
<span style="color:#000000"><code class="language-python"><span style="color:#880000">#! /usr/bin python</span>
<span style="color:#880000"># -*- coding:utf-8 -*-</span>
<span style="color:#000088">from</span> django.contrib <span style="color:#000088">import</span> admin
<span style="color:#000088">from</span> sign.models <span style="color:#000088">import</span> Event, Guest
<span style="color:#880000"># Register your models here.</span>
<span style="color:#000088">class</span> <span style="color:#4f4f4f">EventAdmin</span><span style="color:#4f4f4f">(admin.ModelAdmin)</span>:
list_display = [<span style="color:#009900">'id'</span>, <span style="color:#009900">'name'</span>, <span style="color:#009900">'status'</span>, <span style="color:#009900">'address'</span>, <span style="color:#009900">'start_time'</span>] <span style="color:#880000"># 在admin管理後臺展示更多字段</span>
search_fields = [<span style="color:#009900">'name'</span>] <span style="color:#880000"># 在admin後臺增加搜索欄</span>
list_filter = [<span style="color:#009900">'status'</span>] <span style="color:#880000"># 在admin後臺增加過濾器</span>
<span style="color:#000088">class</span> <span style="color:#4f4f4f">GuestAdmin</span><span style="color:#4f4f4f">(admin.ModelAdmin)</span>:
list_display = [<span style="color:#009900">'realname'</span>, <span style="color:#009900">'phone'</span>, <span style="color:#009900">'email'</span>, <span style="color:#009900">'sign'</span>, <span style="color:#009900">'create_time'</span>, <span style="color:#009900">'event'</span>]
search_fields = [<span style="color:#009900">'realname'</span>, <span style="color:#009900">'phone'</span>]
list_filter = [<span style="color:#009900">'sign'</span>]
<span style="color:#880000"># 在admin管理後臺註冊發佈會表、嘉賓表</span>
admin.site.register(Event, EventAdmin)
admin.site.register(Guest, GuestAdmin)</code></span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
4.3 基本數據訪問
通過如下方法對數據庫中的數據進行訪問:
<span style="color:#000000"><code class="language-syslog">root<span style="color:#4f4f4f">@TEST</span><span style="color:#009900">:/home/test/guest</span><span style="color:#880000"># python manage.py shell</span>
<span style="color:#009900">Python</span> <span style="color:#006666">2.7</span>.<span style="color:#006666">12</span> (default, <span style="color:#009900">Nov</span> <span style="color:#006666">19</span> <span style="color:#006666">2016</span>, <span style="color:#006666">06</span><span style="color:#009900">:</span><span style="color:#006666">48</span><span style="color:#009900">:</span><span style="color:#006666">10</span>)
[<span style="color:#009900">GCC</span> <span style="color:#006666">5.4</span>.<span style="color:#006666">0</span> <span style="color:#006666">20160609</span>] on linux2
<span style="color:#009900">Type</span> <span style="color:#009900">"help"</span>, <span style="color:#009900">"copyright"</span>, <span style="color:#009900">"credits"</span> <span style="color:#000088">or</span> <span style="color:#009900">"license"</span> <span style="color:#000088">for</span> more information.
(<span style="color:#009900">InteractiveConsole</span>)
>>> from sign.models import <span style="color:#009900">Event</span>, <span style="color:#009900">Guest</span> <span style="color:#880000"># 導入sign應用下Model中的Event類、Guest類</span>
>>> <span style="color:#009900">Event</span>.objects.all() <span style="color:#880000"># 通過objects.all()獲取全部對象</span>
<<span style="color:#009900">QuerySet</span> [<<span style="color:#009900">Event</span><span style="color:#009900">:</span> 好友婚禮>]>
>>> <span style="color:#009900">Guest</span>.objects.all()
<<span style="color:#009900">QuerySet</span> [<<span style="color:#009900">Guest</span><span style="color:#009900">:</span> <span style="color:#009900">Guest</span> object>]>
>>> </code></span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
可以看到當我們查詢Event數據表裏的對象時,返回內容是我們添加的記錄的name字段,而當我們查詢Guest表的對象時,返回的卻是對象而不是具體的字段名,這是爲什麼?
因爲在/guest/sign/models.py文件中,我們爲Event類定義了返回的字段名,但是Guest類沒有定義返回的字段名,所以就造成了上述查詢結果的差異。
如果我們也想讓Guest在查詢的時候返回一個字段名比如realname,而不是返回一個對象object,只需要同樣增加如下代碼:
<span style="color:#000000"><code class="language-python"><span style="color:#880000"># 嘉賓表</span>
<span style="color:#000088">class</span> <span style="color:#4f4f4f">Guest</span><span style="color:#4f4f4f">(models.Model)</span>:
……
<span style="color:#000088">def</span> <span style="color:#009900">__unicode__</span><span style="color:#4f4f4f">(self)</span>:
<span style="color:#000088">return</span> self.realname</code></span>
- 1
- 2
- 3
- 4
- 5
- 6
再次查詢Guest的結果就變爲:
<span style="color:#000000"><code><span style="color:#006666">>>> </span>Guest.objects.all()
<QuerySet [<Guest: 好友>]>
<span style="color:#006666">>>> </span></code></span>
- 1
- 2
- 3
插入數據:
<span style="color:#000000"><code class="language-syslog">root<span style="color:#006666">@TEST:/home/test/guest# python manage.py shell</span>
Python <span style="color:#006666">2.7</span><span style="color:#006666">.12</span> (default, Nov <span style="color:#006666">19</span> <span style="color:#006666">2016</span>, <span style="color:#006666">06</span>:<span style="color:#006666">48</span>:<span style="color:#006666">10</span>)
[GCC <span style="color:#006666">5.4</span><span style="color:#006666">.0</span> <span style="color:#006666">20160609</span>] on linux2
Type <span style="color:#009900">"help"</span>, <span style="color:#009900">"copyright"</span>, <span style="color:#009900">"credits"</span> <span style="color:#000088">or</span> <span style="color:#009900">"license"</span> <span style="color:#000088">for</span> more information.
(InteractiveConsole)
<span style="color:#006666">>>> </span><span style="color:#000088">from</span> sign.models <span style="color:#000088">import</span> Event, Guest
<span style="color:#006666">>>> </span><span style="color:#000088">from</span> datetime <span style="color:#000088">import</span> datetime
<span style="color:#006666">>>> </span>e1 = Event(name=<span style="color:#009900">'週末聚會'</span>, limit=<span style="color:#006666">200</span>, status=<span style="color:#000088">True</span>, address=<span style="color:#009900">'北京'</span>, start_time=datetime(<span style="color:#006666">2017</span>,<span style="color:#006666">6</span>,<span style="color:#006666">10</span>,<span style="color:#006666">15</span>,<span style="color:#006666">0</span>,<span style="color:#006666">0</span>))
<span style="color:#006666">>>> </span>e1.save()
/usr/local/lib/python2<span style="color:#006666">.7</span>/dist-packages/django/db/models/fields/__init__.py:<span style="color:#006666">1430</span>: RuntimeWarning: DateTimeField Event.start_time received a naive datetime (<span style="color:#006666">2017</span>-<span style="color:#006666">06</span>-<span style="color:#006666">10</span> <span style="color:#006666">15</span>:<span style="color:#006666">00</span>:<span style="color:#006666">00</span>) <span style="color:#000088">while</span> time zone support <span style="color:#000088">is</span> active.
RuntimeWarning)
<span style="color:#006666">>>> </span></code></span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
這裏與書中略有區別,書中是在插入數據時,指定了id=2,實際上id是數據表中自增字段,插入數據的時候也不可能先去查下id現在是多少了,所以忽略該字段,直接插入數據也是可以的。
忽略結尾時間警告信息: 修改/guest/settings.py文件,設置USE_TZ=False
上面的步驟,先是創建數據,然後調用save()方法保存至數據表中,也可以將兩步合爲一步:
<span style="color:#000000"><code class="language-syslog">>>> <span style="color:#000088">Event</span>.objects.<span style="color:#000088">create</span>(id=<span style="color:#006666">3</span>, name=<span style="color:#009900">'紅米MAX發佈會'</span>, limit=<span style="color:#006666">200</span>, status=<span style="color:#000088">True</span>, address=<span style="color:#009900">'北京會展中心'</span>, start_time=datetime(<span style="color:#006666">2016</span>,<span style="color:#006666">9</span>,<span style="color:#006666">22</span>,<span style="color:#006666">14</span>,<span style="color:#006666">0</span>,<span style="color:#006666">0</span>))
<<span style="color:#000088">Event</span>: 紅米MAX發佈會>
>>> Guest.objects.<span style="color:#000088">create</span>(realname=<span style="color:#009900">'Andy'</span>, phone=<span style="color:#006666">13611001101</span>, email=<span style="color:#009900">'[email protected]'</span>, sign=<span style="color:#000088">False</span>, event_id=<span style="color:#006666">3</span>)
<Guest: Andy>
>>> </code></span>
- 1
- 2
- 3
- 4
- 5
通過指定Event的id=3、Guest的event_id=3,將兩者進行關聯。
查詢數據:
table.objects.create():一步插入數據。
table.objects.get():查詢一條匹配的結果,返回結果爲對象,返回結果不存在報DoesNotExist錯誤。
table.objects.filter():查詢匹配的結果,返回結果爲對象列表,返回結果不存在返回空列表[]。
<span style="color:#000000"><code class="language-syslog"><span style="color:#880000"># 使用get()查詢name=紅米MAX發佈會的記錄</span>
<span style="color:#006666">>>> </span>e1 = Event.objects.get(name=<span style="color:#009900">'紅米MAX發佈會'</span>)
<span style="color:#880000"># 返回的結果e1是個對象</span>
<span style="color:#006666">>>> </span>e1
<Event: 紅米MAX發佈會>
<span style="color:#880000"># 從e1對象獲取start_time的值</span>
<span style="color:#006666">>>> </span>e1.start_time
datetime.datetime(<span style="color:#006666">2016</span>, <span style="color:#006666">9</span>, <span style="color:#006666">22</span>, <span style="color:#006666">14</span>, <span style="color:#006666">0</span>, tzinfo=<UTC>)
<span style="color:#880000"># 也可以不賦值給e1,而是直接在get()方法後加上字段名來獲取對應的值</span>
<span style="color:#006666">>>> </span>Event.objects.get(name=<span style="color:#009900">'紅米MAX發佈會'</span>).status
<span style="color:#000088">True</span>
<span style="color:#880000"># 同理查詢紅米MAX發佈會的地點</span>
<span style="color:#006666">>>> </span>Event.objects.get(name=<span style="color:#009900">'紅米MAX發佈會'</span>).address
<span style="color:#009900">u'\u5317\u4eac\u4f1a\u5c55\u4e2d\u5fc3'</span>
<span style="color:#880000"># 如果查詢條件結果不存在則會報錯DoesNotExist</span>
<span style="color:#006666">>>> </span>Event.objects.get(name=<span style="color:#009900">'發佈會'</span>).address
Traceback (most recent call last):
File <span style="color:#009900">"<console>"</span>, line <span style="color:#006666">1</span>, <span style="color:#000088">in</span> <module>
File <span style="color:#009900">"/usr/local/lib/python2.7/dist-packages/django/db/models/manager.py"</span>, line <span style="color:#006666">85</span>, <span style="color:#000088">in</span> manager_method
<span style="color:#000088">return</span> getattr(self.get_queryset(), name)(*args, **kwargs)
File <span style="color:#009900">"/usr/local/lib/python2.7/dist-packages/django/db/models/query.py"</span>, line <span style="color:#006666">385</span>, <span style="color:#000088">in</span> get
self.model._meta.object_name
DoesNotExist: Event matching query does <span style="color:#000088">not</span> exist.
<span style="color:#880000"># 使用filter來過濾指定條件獲取對象列表,注意name和contains之間是雙下劃線</span>
<span style="color:#006666">>>> </span>e2 = Event.objects.filter(name__contains=<span style="color:#009900">'發佈會'</span>)
<span style="color:#880000"># 返回結果e2是個結果列表</span>
<span style="color:#006666">>>> </span>e2
<QuerySet [<Event: 紅米MAX發佈會>]>
<span style="color:#880000"># 既然是列表就可以用如下方式訪問其中數據</span>
<span style="color:#006666">>>> </span>e2[<span style="color:#006666">0</span>]
<Event: 紅米MAX發佈會>
<span style="color:#880000"># 關聯查詢示例,先使用get()方法獲取查詢結果對象</span>
<span style="color:#006666">>>> </span>g1 = Guest.objects.get(phone=<span style="color:#009900">'13611001101'</span>)
<span style="color:#880000"># 關聯查詢phone爲136……嘉賓所對應的發佈會信息event</span>
<span style="color:#006666">>>> </span>g1.event
<Event: 紅米MAX發佈會>
<span style="color:#880000"># 該嘉賓對應發佈會的名稱</span>
<span style="color:#006666">>>> </span>g1.event.name
<span style="color:#009900">u'\u7ea2\u7c73MAX\u53d1\u5e03\u4f1a'</span>
<span style="color:#880000"># 該嘉賓對應發佈會的地址</span>
<span style="color:#006666">>>> </span>g1.event.address
<span style="color:#009900">u'\u5317\u4eac\u4f1a\u5c55\u4e2d\u5fc3'</span>
<span style="color:#006666">>>> </span></code></span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
刪除數據:
table.objects.get().delete():獲取指定查詢條件的結果對象並刪除。
獲取查詢對象,調用delete()方法進行刪除:
<span style="color:#000000"><code class="language-syslog"><span style="color:#880000"># 先獲取查詢對象,再調用delete()方法刪除</span>
<span style="color:#006666">>>> </span>g2 = Guest.objects.get(phone=<span style="color:#009900">'13611001101'</span>)
<span style="color:#006666">>>> </span>g2.delete()
(<span style="color:#006666">1</span>, {<span style="color:#009900">u'sign.Guest'</span>: <span style="color:#006666">1</span>})
<span style="color:#006666">>>> </span>
<span style="color:#880000"># 不可以重複刪除</span>
<span style="color:#006666">>>> </span>Guest.objects.get(phone=<span style="color:#009900">'13611001101'</span>).delete()
Traceback (most recent call last):
File <span style="color:#009900">"<console>"</span>, line <span style="color:#006666">1</span>, <span style="color:#000088">in</span> <module>
File <span style="color:#009900">"/usr/local/lib/python2.7/dist-packages/django/db/models/manager.py"</span>, line <span style="color:#006666">85</span>, <span style="color:#000088">in</span> manager_method
<span style="color:#000088">return</span> getattr(self.get_queryset(), name)(*args, **kwargs)
File <span style="color:#009900">"/usr/local/lib/python2.7/dist-packages/django/db/models/query.py"</span>, line <span style="color:#006666">385</span>, <span style="color:#000088">in</span> get
self.model._meta.object_name
DoesNotExist: Guest matching query does <span style="color:#000088">not</span> exist.
<span style="color:#006666">>>> </span></code></span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
更新數據:
table.objects.select_for_update().filter().update():過濾指定條件的對象列表並調用update()方法更新指定數據。
<span style="color:#000000"><code class="language-syslog"><span style="color:#880000"># 先獲取查詢對象,再更新指定數據,最後保存至數據表</span>
<span style="color:#006666">>>> </span>g3 = Guest.objects.get(phone=<span style="color:#009900">'13611001101'</span>)
<span style="color:#006666">>>> </span>g3.realname = <span style="color:#009900">'Andy2'</span>
<span style="color:#006666">>>> </span>g3.save()
<span style="color:#006666">>>> </span>
<span style="color:#880000"># 直接使用select_for_update方法過濾指定條件對象列表再調用update方法更新數據並保存至數據表</span>
<span style="color:#006666">>>> </span>Guest.objects.select_for_update().filter(phone=<span style="color:#009900">'13611001101'</span>).update(realname=<span style="color:#009900">'Andy2'</span>)
<span style="color:#006666">1</span>
<span style="color:#006666">>>> </span></code></span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
4.4 SQLite管理工具
Pass
4.5 配置MySQL
安裝MySQL
Pass
安裝MySQL-Python驅動
如果使用Python2版本:安裝MySQL-Python
如果使用Python3版本:安裝PyMySQL
MySQL基本操作
-
show databases; # 查看當前數據庫下面的所有庫
-
use test; # 切換到test庫
-
show tables; #查看test庫下面所有表
-
show global variables like ‘port’; #查看MySQL端口號
-
CREATE DATABASE guest CHARACTER SET utf8; #創建guest數據庫
書中使用如下代碼演示瞭如何通過pymysql庫對數據庫進行操作,插入數據,但是書中忽略了一個重要前提,我們從開始新建Django項目的時候,就使用的是SQLite3數據庫,並沒有用MySQL進行過任何操作,這如果直接按代碼執行,只會提示錯誤沒有guest表,對啊,是沒有啊,上面只是在基本操作裏,新建了guest庫,但是沒有在guest庫下新建表,所以在執行插入數據的代碼之前,我們應該先新建兩個表:sign_event、sign_guest
<span style="color:#000000"><code class="language-sql"># 創建sign_event表
<span style="color:#000088">CREATE</span> <span style="color:#000088">TABLE</span> <span style="color:#009900">`sign_event`</span> (
<span style="color:#009900">`id`</span> <span style="color:#000088">int</span>(<span style="color:#006666">11</span>) <span style="color:#000088">NOT</span> <span style="color:#000088">NULL</span> AUTO_INCREMENT,
<span style="color:#009900">`name`</span> <span style="color:#000088">varchar</span>(<span style="color:#006666">100</span>) <span style="color:#000088">NOT</span> <span style="color:#000088">NULL</span>,
<span style="color:#009900">`limit`</span> <span style="color:#000088">integer</span>,
<span style="color:#009900">`status`</span> BOOLEAN,
<span style="color:#009900">`address`</span> <span style="color:#000088">varchar</span>(<span style="color:#006666">200</span>) <span style="color:#000088">NOT</span> <span style="color:#000088">NULL</span>,
<span style="color:#009900">`start_time`</span> DATETIME,
<span style="color:#009900">`create_time`</span> DATETIME <span style="color:#000088">DEFAULT</span> <span style="color:#000088">CURRENT_TIMESTAMP</span>,
<span style="color:#000088">PRIMARY</span> <span style="color:#000088">KEY</span> (<span style="color:#009900">`id`</span>)
)ENGINE=InnoDB <span style="color:#000088">DEFAULT</span> CHARSET=utf8;
<span style="color:#000088">alter</span> <span style="color:#000088">table</span> <span style="color:#009900">`sign_event`</span> <span style="color:#000088">add</span> index id(id);</code></span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
<span style="color:#000000"><code class="language-sql"># 創建sign_guest表
<span style="color:#000088">CREATE</span> <span style="color:#000088">TABLE</span> <span style="color:#009900">`sign_guest`</span> (
<span style="color:#009900">`id`</span> <span style="color:#000088">int</span>(<span style="color:#006666">11</span>) <span style="color:#000088">NOT</span> <span style="color:#000088">NULL</span> AUTO_INCREMENT,
<span style="color:#009900">`event_id`</span> <span style="color:#000088">int</span>(<span style="color:#006666">11</span>) <span style="color:#000088">NOT</span> <span style="color:#000088">NULL</span>,
<span style="color:#009900">`realname`</span> <span style="color:#000088">varchar</span>(<span style="color:#006666">64</span>) <span style="color:#000088">NOT</span> <span style="color:#000088">NULL</span>,
<span style="color:#009900">`phone`</span> <span style="color:#000088">varchar</span>(<span style="color:#006666">16</span>) <span style="color:#000088">NOT</span> <span style="color:#000088">NULL</span>,
<span style="color:#009900">`email`</span> <span style="color:#000088">varchar</span>(<span style="color:#006666">254</span>) <span style="color:#000088">NOT</span> <span style="color:#000088">NULL</span>,
<span style="color:#009900">`sign`</span> BOOLEAN,
<span style="color:#009900">`create_time`</span> DATETIME <span style="color:#000088">DEFAULT</span> <span style="color:#000088">CURRENT_TIMESTAMP</span>,
<span style="color:#000088">PRIMARY</span> <span style="color:#000088">KEY</span> (<span style="color:#009900">`id`</span>),
<span style="color:#000088">FOREIGN</span> <span style="color:#000088">KEY</span> (<span style="color:#009900">`event_id`</span>) <span style="color:#000088">REFERENCES</span> sign_event(id)
)ENGINE=InnoDB <span style="color:#000088">DEFAULT</span> CHARSET=utf8;
<span style="color:#000088">alter</span> <span style="color:#000088">table</span> <span style="color:#009900">`sign_guest`</span> <span style="color:#000088">add</span> index id(id);
<span style="color:#000088">alter</span> <span style="color:#000088">table</span> <span style="color:#009900">`sign_guest`</span> <span style="color:#000088">add</span> <span style="color:#000088">unique</span>(event_id, phone);</code></span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
<span style="color:#000000"><code class="language-python"><span style="color:#880000">#! /usr/bin python</span>
<span style="color:#880000"># -*- coding: utf-8 -*-</span>
<span style="color:#000088">from</span> pymysql <span style="color:#000088">import</span> cursors, connect
<span style="color:#880000"># 連接數據庫</span>
conn = connect(host=<span style="color:#009900">'127.0.0.1'</span>,
user=<span style="color:#009900">'root'</span>,
password=<span style="color:#009900">'nsfocus'</span>,
db=<span style="color:#009900">'guest'</span>,
charset=<span style="color:#009900">'utf8mb4'</span>,
cursorclass=cursors.DictCursor)
<span style="color:#000088">try</span>:
<span style="color:#000088">with</span> conn.cursor() <span style="color:#000088">as</span> cursor:
<span style="color:#880000"># 創建發佈會數據</span>
sql = <span style="color:#009900">'INSERT INTO sign_event (name, `limit`, status, address, start_time, create_time) VALUES ("紅米MAX發佈會", 200, 1, "北京會展中心", "2016-09-22 14:00:00", NOW());'</span>
cursor.execute(sql)
<span style="color:#880000"># 提交事務</span>
conn.commit()
<span style="color:#880000"># 創建嘉賓數據</span>
sql = <span style="color:#009900">'INSERT INTO sign_guest (realname, phone, email, `sign`, event_id, create_time) VALUES ("Tom", 18800110002, "[email protected]", 0, 1, NOW());'</span>
cursor.execute(sql)
<span style="color:#880000"># 提交事務</span>
conn.commit()
<span style="color:#000088">with</span> conn.cursor() <span style="color:#000088">as</span> cursor:
<span style="color:#880000"># 查詢剛剛添加的嘉賓</span>
sql = <span style="color:#009900">'SELECT realname, phone, email, sign FROM sign_guest WHERE phone=%s'</span>
cursor.execute(sql, (<span style="color:#009900">'18800110002'</span>,))
result = cursor.fetchone()
<span style="color:#000088">print</span> result
<span style="color:#000088">finally</span>:
conn.close()</code></span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
在這個過程中遇到一些問題:
我們安裝了MySQL數據庫後,雖然創建了guest數據庫,但是並沒有創建發佈會表、嘉賓表,所以如果按書中直接執行此py文件,一定會報錯,提示guest表不存在!!!
如何解決這個問題,很簡單,參考之前models.py文件裏的設置,先創建好兩個數據表event、guest,再來執行這個py文件就不會出錯了!
引申出兩個問題:
-
如何使MySQL服務端不只是監聽本地127.0.0.1這個地址?
- 這就需要修改配置文件/etc/mysql/mysql.conf.d/mysqld.cnf,將其中的bind-address由127.0.0.1修改爲0.0.0.0,重啓MySQL服務即可/etc/init.d/mysql restart;
-
如果通過遠程來訪問MySQL服務端?
-
對MySQL實在不熟,發現用起來很多基礎知識都不懂,查了好半天的資料才找到問題根本,原本以爲在配置文件裏修改各什麼安全設置就能搞定,然而並不是這麼回事,這是由於root用戶在mysql數據庫中存儲的host字段的限制;
-
首先在本地登錄MySQL數據庫:mysql -u root -p,然後切換至mysql數據庫:use mysql;,查看user表中root帳號的記錄:select * from user where user=’root’;,可以發現host字段的值爲localhost,這就是爲什麼遠程主機無法使用root帳號來訪問的原因了;
-
解決辦法就是給host字段增加遠程主機的IP:grant all privileges on *.* to root@”遠程主機IP地址” identified by “root帳號對應的密碼”;,這就相當於給遠程IP賦予了所有的權限,包括遠程訪問的權限,然後輸入:flush privileges;,這相當於是重新加載一下mysql權限;
-
至此,就又可以從本地訪問也能從遠程主機訪問了。
-
pymysql裏的幾個重要函數:
-
connect():建立數據庫連接;
-
cursor():獲取數據庫操作遊標;
-
execute():執行SQL語句;
-
commit():提交數據庫執行;
-
close():關閉數據庫連接;
在Django中配置MyDQL
修改配置文件/guest/settings.py:
<span style="color:#000000"><code class="language-python">DATABASES = {
<span style="color:#009900">'default'</span>: {
<span style="color:#009900">'ENGINE'</span>: <span style="color:#009900">'django.db.backends.mysql'</span>,
<span style="color:#009900">'HOST'</span>: <span style="color:#009900">'127.0.0.1'</span>,
<span style="color:#009900">'PORT'</span>: <span style="color:#009900">'3306'</span>,
<span style="color:#009900">'NAME'</span>: <span style="color:#009900">'guest'</span>,
<span style="color:#009900">'USER'</span>: <span style="color:#009900">'root'</span>,
<span style="color:#009900">'PASSWORD'</span>: <span style="color:#009900">'123456'</span>,
<span style="color:#009900">'OPTIONS'</span>: {
<span style="color:#009900">'init_command'</span>: <span style="color:#009900">"SET sql_mode='STRICT_TRANS_TABLES'"</span>,
},
}
}</code></span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
注意:需要先把原數據庫註釋掉。
蟲師的是在本章節,纔講解了如何將SQLite3裏的數據同步至MySQL裏,因爲並不能這樣複製數據,但是可以使用:
python manage.py migrate
命令來重新執行數據庫同步,是數據模型重新在MySQL數據庫中生成表。這也就是上面我提到的蟲師缺少的部分,只不過我上面是用笨方法手工重建MySQL的數據表,而這裏是使用數據同步命令。
但是在執行此命令的時候也會遇到問題,即:“如何讓Django通過PyMySQL來連接數據庫”?
需要在/guest/__init__.py中加入如下代碼:
<span style="color:#000000"><code class="language-python"><span style="color:#000088">import</span> pymysql
pymysql.install_as_MySQLdb()</code></span>
- 1
- 2
- 3
再次執行migrate命令就不會出錯了,由於更換了MySQL數據庫,所以admin後臺的超級管理員的賬號也要重建。
MySQL管理工具
-
Navicat
-
SQLyog
至此第4章的全部內容都結束了。本章的內容主要圍繞Django的Model層,也就是數據層做簡要介紹。主要知識點就是model.py以及數據在管理後臺admin.py裏如何展示。