第4章 Django模型
? 在Web 應(yīng)用中,主觀邏輯經(jīng)常牽涉到與數(shù)據(jù)庫的交互。以數(shù)據(jù)庫驅(qū)動(dòng)網(wǎng)站在后臺(tái)連接數(shù)據(jù)庫服務(wù)器,從中取出一些數(shù)據(jù),然后在Web 頁面用漂亮的格式展示這些數(shù)據(jù)。這個(gè)網(wǎng)站也可能會(huì)向訪問者提供修改數(shù)據(jù)庫數(shù)據(jù)的方法。許多復(fù)雜的網(wǎng)站都提供了以上兩個(gè)功能的某種結(jié)合。
? 對(duì)于我們的發(fā)布會(huì)簽到系統(tǒng)來說,也是以數(shù)據(jù)管理為主的網(wǎng)站,主要管理發(fā)布會(huì)和嘉賓數(shù)據(jù)。有一個(gè)觀點(diǎn),對(duì)于數(shù)據(jù)驅(qū)動(dòng)的Web 系統(tǒng),數(shù)據(jù)庫表的設(shè)計(jì)完成,就相當(dāng)于Web 系統(tǒng)已經(jīng)完成了一半,可見數(shù)據(jù)庫表的設(shè)計(jì)難度,以及在Web 開發(fā)中的重要性。
4.1 設(shè)計(jì)系統(tǒng)表
Django 提供完善的模型(model)層主要用來創(chuàng)建和存取數(shù)據(jù),不需要我們直接對(duì)數(shù)據(jù)庫操作。
Django模型的基礎(chǔ)知識(shí):
- 每個(gè)模型是一個(gè)Python類,繼承django.db.models.Model類
- 該模型的每個(gè)屬性表示一個(gè)數(shù)據(jù)庫表字段
- 所有這一切,已經(jīng)給了你一個(gè)自動(dòng)生成數(shù)據(jù)庫訪問的API
本例所需的模型,修改/guest/sign/models.py文件:
#! /usr/bin python
# -*- coding:utf-8 -*-
from __future__ import unicode_literals
from django.db import models
# Create your models here.
# 發(fā)布會(huì)表
class Event(models.Model):
name = models.CharField(max_length=100) # 發(fā)布會(huì)標(biāo)題
limit = models.IntegerField() # 參加人數(shù)
status = models.BooleanField() # 狀態(tài)
address = models.CharField(max_length=200) # 地址
start_time = models.DateTimeField('events time') # 發(fā)布會(huì)時(shí)間
create_time = models.DateTimeField(auto_now=True) # 創(chuàng)建時(shí)間(自動(dòng)獲取當(dāng)前時(shí)間)
def __str__(self):
return self.name
# 嘉賓表
class Guest(models.Model):
event = models.ForeignKey(Event) # 外鍵,關(guān)聯(lián)發(fā)布會(huì)id
realname = models.CharField(max_length=64) # 姓名
phone = models.CharField(max_length=16) # 電話
email = models.EmailField() # 郵箱
sign = models.BooleanField() # 簽到狀態(tài)
create_time = models.DateTimeField(auto_now=True) # 創(chuàng)建時(shí)間(自動(dòng)獲取當(dāng)前時(shí)間)
class Meta:
unique_together = ("event", "phone")
def __str__(self):
return self.name
發(fā)布會(huì)表(Event 類)和嘉賓表(Guest 類)
注意:
- 發(fā)布會(huì)表和嘉賓表中默認(rèn)都會(huì)生成自增id,而我們?cè)趧?chuàng)建模型時(shí)不需要聲明該字段。
- 發(fā)布會(huì)表中增加了status 字段用于表示發(fā)布會(huì)的狀態(tài)是否開啟,用于控制該發(fā)布會(huì)是否可用。
- 嘉賓表中通過event_id 關(guān)聯(lián)發(fā)布會(huì)表,一條嘉賓信息一定所屬于某一場(chǎng)發(fā)布會(huì)。
- 對(duì)于一場(chǎng)發(fā)布會(huì)來說,一般會(huì)選擇手機(jī)號(hào)作為一位嘉賓的驗(yàn)證信息,所以,對(duì)于一場(chǎng)發(fā)布會(huì)來說,手機(jī)號(hào)必須是唯一。除了嘉賓id 外,這里通過發(fā)布會(huì)id +手機(jī)號(hào)來做為聯(lián)合主鍵。
- python3使用str()方法、python2使用unicode()方法,顯示對(duì)應(yīng)字段。
Django模型字段常用類型
| 類型 | 說明 |
|---|---|
| AutoField | 一個(gè)IntegerField類型的自動(dòng)增量 |
| BooleanField | 用于存放布爾類型的數(shù)據(jù)(True or False) |
| CharField | 用于存放字符型的數(shù)據(jù),需要指定長(zhǎng)度max_length |
| DateField | 用于存放日期類型的數(shù)據(jù),格式為:YYYY-MM-DD |
| DecimalField | 用于存放小數(shù)型的數(shù)據(jù) |
| EmailField | 用于存放電子郵件類型的數(shù)據(jù) |
| FilePathField | 用于存放文件路徑類型的數(shù)據(jù) |
| FloatField | 用于存放浮點(diǎn)型的數(shù)據(jù) |
| IntegerField | 用于存放整數(shù)類型的數(shù)據(jù),范圍是:-2147483648至2147483647 |
| BigIntegerField | 用于存放大整數(shù)類型的數(shù)據(jù),最大支持:9223372036854775807 |
| GenericIPAdressField | 用于存放IP地址類型的數(shù)據(jù),同時(shí)支持IPv4、IPv6,字符串格式 |
| NullBooleanField | 類似BooleanField,但是允許填寫NULL |
| PositiveIntegerField | 用于存放正數(shù)或0的整數(shù)類型的數(shù)據(jù),范圍是:0-2147483647 |
| PositiveSmallIntegerField | 類似PositiveIntegerField,但是范圍是:0-32767 |
| SlugField | Slug是短標(biāo)簽,只包含字母、數(shù)字、下劃線或字符,它通常在網(wǎng)址中使用,需要定義max_length |
| SmallIntegerField | 類似IntegerField,但是范圍是:-32768至32767 |
| TextField | 用于存放文本類型的數(shù)據(jù) |
| TimeField | 用于存放時(shí)間類型的數(shù)據(jù),格式為:HH:MM[:ss[.uuuuuu]] |
| URLField | 用于存放URL地址 |
| BinaryField | 用于存放原始二進(jìn)制類型的數(shù)據(jù) |
詳細(xì)內(nèi)容可參考官方文檔:
https://docs.djangoproject.com/en/1.10/ref/models/fields/
使用如下命令進(jìn)行數(shù)據(jù)庫表的初始化和創(chuàng)建(遷移):
\guest>python manage.py makemigrations sign
\guest>python manage.py migrate
4.2 admin后臺(tái)管理
將上面創(chuàng)建的發(fā)布會(huì)表、嘉賓表,也加入到admin后臺(tái)進(jìn)行圖形化的管理:
修改/guest/sign/admin.py文件:
from django.contrib import admin
from sign.models import Event, Guest
# Register your models here.
admin.site.register(Event)
admin.site.register(Guest)
通過管理頁面隨意增加一條發(fā)布會(huì)記錄,我這里在增加一條中文記錄的時(shí)候,出現(xiàn)了編碼錯(cuò)誤的提示:
UnicodeEncodeError at /admin/sign/event/add/
看這意思是中文編碼問題,印象當(dāng)中之前看Django官方文檔的時(shí)候,有關(guān)于中文編碼的問題,于是翻了下之前的筆記,發(fā)現(xiàn)是修改/guest/settings.py里的MIDDLEWARE配置,增加一條:
django.middleware.locale.LocaleMiddleware
但是這里將Django的admin管理后臺(tái)的展示從英文變成了本地語言中文,對(duì)于上面遇到的錯(cuò)誤還是沒有幫助,哎,不應(yīng)該呀,蟲師都能在書中增加一條中文記錄,沒理由我這里完全按照蟲師講解的一步一步操作過來的會(huì)遇到錯(cuò)誤啊,仔細(xì)回頭查看models.py發(fā)現(xiàn)了一個(gè)小問題,蟲師在書中也提到了只是自己當(dāng)時(shí)忽略了,蟲師使用的是python3,而我使用的是python2,在展示列表的函數(shù)里,蟲師使用的是str,而我完全照搬書中的代碼,也使用了str,這里就出錯(cuò)了,如果是python2,應(yīng)該使用unicode才對(duì),修改代碼:
# 發(fā)布會(huì)表
class Event(models.Model):
name = models.CharField(max_length=100) # 發(fā)布會(huì)標(biāo)題
limit = models.IntegerField() # 參加人數(shù)
status = models.BooleanField() # 狀態(tài)
address = models.CharField(max_length=200) # 地址
start_time = models.DateTimeField('events time') # 發(fā)布會(huì)時(shí)間
create_time = models.DateTimeField(auto_now=True) # 創(chuàng)建時(shí)間(自動(dòng)獲取當(dāng)前時(shí)間)
#def __str__(self):
def __unicode__(self):
return self.name
再次添加中文記錄,成功,問題解決,后續(xù)對(duì)于不同版本使用的不同函數(shù),還是要注意??!
在管理后臺(tái)列表中顯示更多字段:
修改/guest/sign/admin.py文件:
#! /usr/bin python
# -*- coding:utf-8 -*-
from django.contrib import admin
from sign.models import Event, Guest
# Register your models here.
# 在admin管理后臺(tái)展示更多字段
class EventAdmin(admin.ModelAdmin):
list_display = ['id', 'name', 'status', 'address', 'start_time']
class GuestAdmin(admin.ModelAdmin):
list_display = ['realname', 'phone', 'email', 'sign', 'create_time', 'event']
# 在admin管理后臺(tái)注冊(cè)發(fā)布會(huì)表、嘉賓表
admin.site.register(Event, EventAdmin)
admin.site.register(Guest, GuestAdmin)
注意:
- 新建EventAdmin類繼承admin.ModelAdmin類,其中ModelAdmin提供了很多自定義管理工具;
- list_display數(shù)組內(nèi)是顯示的字段名,必須存在于數(shù)據(jù)表中。
在管理后臺(tái)增加搜索欄、過濾器:
還是修改/guest/sign/admin.py文件:
#! /usr/bin python
# -*- coding:utf-8 -*-
from django.contrib import admin
from sign.models import Event, Guest
# Register your models here.
class EventAdmin(admin.ModelAdmin):
list_display = ['id', 'name', 'status', 'address', 'start_time'] # 在admin管理后臺(tái)展示更多字段
search_fields = ['name'] # 在admin后臺(tái)增加搜索欄
list_filter = ['status'] # 在admin后臺(tái)增加過濾器
class GuestAdmin(admin.ModelAdmin):
list_display = ['realname', 'phone', 'email', 'sign', 'create_time', 'event']
search_fields = ['realname', 'phone']
list_filter = ['sign']
# 在admin管理后臺(tái)注冊(cè)發(fā)布會(huì)表、嘉賓表
admin.site.register(Event, EventAdmin)
admin.site.register(Guest, GuestAdmin)
4.3 基本數(shù)據(jù)訪問
通過如下方法對(duì)數(shù)據(jù)庫中的數(shù)據(jù)進(jìn)行訪問:
root@TEST:/home/test/guest# python manage.py shell
Python 2.7.12 (default, Nov 19 2016, 06:48:10)
[GCC 5.4.0 20160609] on linux2
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from sign.models import Event, Guest # 導(dǎo)入sign應(yīng)用下Model中的Event類、Guest類
>>> Event.objects.all() # 通過objects.all()獲取全部對(duì)象
<QuerySet [<Event: 這是一個(gè)event>]>
>>> Guest.objects.all()
<QuerySet [<Guest: 這是一個(gè)guest>]>
>>>
可以看到當(dāng)我們查詢Event數(shù)據(jù)表里的對(duì)象時(shí),返回內(nèi)容是我們添加的記錄的name字段,而當(dāng)我們查詢Guest表的對(duì)象時(shí),返回的卻是對(duì)象而不是具體的字段名,這是為什么?
因?yàn)樵?guest/sign/models.py文件中,我們?yōu)镋vent類定義了返回的字段名,但是Guest類沒有定義返回的字段名,所以就造成了上述查詢結(jié)果的差異。
如果我們也想讓Guest在查詢的時(shí)候返回一個(gè)字段名比如realname,而不是返回一個(gè)對(duì)象object,只需要同樣增加如下代碼:
# 嘉賓表
class Guest(models.Model):
……
def __unicode__(self):
return self.realname
再次查詢Guest的結(jié)果就變?yōu)椋?/p>
>>> Guest.objects.all()
<QuerySet [<Guest: 好友>]>
>>>
插入數(shù)據(jù):
root@TEST:/home/test/guest# python manage.py shell
Python 2.7.12 (default, Nov 19 2016, 06:48:10)
[GCC 5.4.0 20160609] on linux2
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from sign.models import Event, Guest
>>> from datetime import datetime
>>> e1 = Event(name='周末聚會(huì)', limit=200, status=True, address='北京', start_time=datetime(2017,6,10,15,0,0))
>>> e1.save()
/usr/local/lib/python2.7/dist-packages/django/db/models/fields/__init__.py:1430: RuntimeWarning: DateTimeField Event.start_time received a naive datetime (2017-06-10 15:00:00) while time zone support is active.
RuntimeWarning)
>>>
這里與書中略有區(qū)別,書中是在插入數(shù)據(jù)時(shí),指定了id=2,實(shí)際上id是數(shù)據(jù)表中自增字段,插入數(shù)據(jù)的時(shí)候也不可能先去查下id現(xiàn)在是多少了,所以忽略該字段,直接插入數(shù)據(jù)也是可以的。
忽略結(jié)尾時(shí)間警告信息: 修改/guest/settings.py文件,設(shè)置USE_TZ=False
上面的步驟,先是創(chuàng)建數(shù)據(jù),然后調(diào)用save()方法保存至數(shù)據(jù)表中,也可以將兩步合為一步:
>>> Event.objects.create(id=3, name='紅米MAX發(fā)布會(huì)', limit=200, status=True, address='北京會(huì)展中心', start_time=datetime(2016,9,22,14,0,0))
<Event: 紅米MAX發(fā)布會(huì)>
>>> Guest.objects.create(realname='Andy', phone=13611001101, email='andy@mail.com', sign=False, event_id=3)
<Guest: Andy>
>>>
通過指定Event的id=3、Guest的event_id=3,將兩者進(jìn)行關(guān)聯(lián)。
查詢數(shù)據(jù):
table.objects.create():一步插入數(shù)據(jù)。
table.objects.get():查詢一條匹配的結(jié)果,返回結(jié)果為對(duì)象,返回結(jié)果不存在報(bào)DoesNotExist錯(cuò)誤。
table.objects.filter():查詢匹配的結(jié)果,返回結(jié)果為對(duì)象列表,返回結(jié)果不存在返回空列表[]。
# 使用get()查詢name=紅米MAX發(fā)布會(huì)的記錄
>>> e1 = Event.objects.get(name='紅米MAX發(fā)布會(huì)')
# 返回的結(jié)果e1是個(gè)對(duì)象
>>> e1
<Event: 紅米MAX發(fā)布會(huì)>
# 從e1對(duì)象獲取start_time的值
>>> e1.start_time
datetime.datetime(2016, 9, 22, 14, 0, tzinfo=<UTC>)
# 也可以不賦值給e1,而是直接在get()方法后加上字段名來獲取對(duì)應(yīng)的值
>>> Event.objects.get(name='紅米MAX發(fā)布會(huì)').status
True
# 同理查詢紅米MAX發(fā)布會(huì)的地點(diǎn)
>>> Event.objects.get(name='紅米MAX發(fā)布會(huì)').address
u'\u5317\u4eac\u4f1a\u5c55\u4e2d\u5fc3'
# 如果查詢條件結(jié)果不存在則會(huì)報(bào)錯(cuò)DoesNotExist
>>> Event.objects.get(name='發(fā)布會(huì)').address
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/usr/local/lib/python2.7/dist-packages/django/db/models/manager.py", line 85, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/django/db/models/query.py", line 385, in get
self.model._meta.object_name
DoesNotExist: Event matching query does not exist.
# 使用filter來過濾指定條件獲取對(duì)象列表,注意name和contains之間是雙下劃線
>>> e2 = Event.objects.filter(name__contains='發(fā)布會(huì)')
# 返回結(jié)果e2是個(gè)結(jié)果列表
>>> e2
<QuerySet [<Event: 紅米MAX發(fā)布會(huì)>]>
# 既然是列表就可以用如下方式訪問其中數(shù)據(jù)
>>> e2[0]
<Event: 紅米MAX發(fā)布會(huì)>
# 關(guān)聯(lián)查詢示例,先使用get()方法獲取查詢結(jié)果對(duì)象
>>> g1 = Guest.objects.get(phone='13611001101')
# 關(guān)聯(lián)查詢phone為136……嘉賓所對(duì)應(yīng)的發(fā)布會(huì)信息event
>>> g1.event
<Event: 紅米MAX發(fā)布會(huì)>
# 該嘉賓對(duì)應(yīng)發(fā)布會(huì)的名稱
>>> g1.event.name
u'\u7ea2\u7c73MAX\u53d1\u5e03\u4f1a'
# 該嘉賓對(duì)應(yīng)發(fā)布會(huì)的地址
>>> g1.event.address
u'\u5317\u4eac\u4f1a\u5c55\u4e2d\u5fc3'
>>>
刪除數(shù)據(jù):
table.objects.get().delete():獲取指定查詢條件的結(jié)果對(duì)象并刪除。
獲取查詢對(duì)象,調(diào)用delete()方法進(jìn)行刪除:
# 先獲取查詢對(duì)象,再調(diào)用delete()方法刪除
>>> g2 = Guest.objects.get(phone='13611001101')
>>> g2.delete()
(1, {u'sign.Guest': 1})
>>>
# 不可以重復(fù)刪除
>>> Guest.objects.get(phone='13611001101').delete()
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/usr/local/lib/python2.7/dist-packages/django/db/models/manager.py", line 85, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/django/db/models/query.py", line 385, in get
self.model._meta.object_name
DoesNotExist: Guest matching query does not exist.
>>>
更新數(shù)據(jù):
table.objects.select_for_update().filter().update():過濾指定條件的對(duì)象列表并調(diào)用update()方法更新指定數(shù)據(jù)。
# 先獲取查詢對(duì)象,再更新指定數(shù)據(jù),最后保存至數(shù)據(jù)表
>>> g3 = Guest.objects.get(phone='13611001101')
>>> g3.realname = 'Andy2'
>>> g3.save()
>>>
# 直接使用select_for_update方法過濾指定條件對(duì)象列表再調(diào)用update方法更新數(shù)據(jù)并保存至數(shù)據(jù)表
>>> Guest.objects.select_for_update().filter(phone='13611001101').update(realname='Andy2')
1
>>>
4.4 SQLite管理工具
SQLiteManager 是一個(gè)支持多國語言基于Web 的SQLite 數(shù)據(jù)庫管理工具,它的特點(diǎn)包括多數(shù)據(jù)庫管理,創(chuàng)建和連接;表格,數(shù)據(jù),索引操作;視圖,觸發(fā)器,和自定義函數(shù)管理,數(shù)據(jù)導(dǎo)入/導(dǎo)出,數(shù)據(jù)庫結(jié)構(gòu)導(dǎo)出等。
在Firefox 瀏覽器插件庫中可以搜索到SQLiteManager,所以,這裝起來非常方便。打開Firefox 瀏覽器,菜單欄“工具”-->“添加組件”,搜索“SQLiteManager”安裝,并重啟動(dòng)Firefox 瀏覽。
SQLiteStudio 是一款SQLite 數(shù)據(jù)庫可視化工具,是使用SQLite 數(shù)據(jù)庫開發(fā)應(yīng)用的必備軟件,軟件無需安裝,下載后解壓即可使用,很小巧但很好用,綠色中文版本。比起其它SQLite 管理工具,我喜歡用這個(gè)。很方便易用,不用安裝的單個(gè)可執(zhí)行文件,支持中文。
4.5 配置MySQL
安裝MySQL
http://www.itdecent.cn/p/f6c1ed073ecd
網(wǎng)上也有很多教程啦~
安裝MySQL-Python驅(qū)動(dòng)
如果使用Python2版本:安裝MySQL-Python
如果使用Python3版本:安裝PyMySQL
MySQL基本操作
- show databases; # 查看當(dāng)前數(shù)據(jù)庫下面的所有庫
- use test; # 切換到test庫
- show tables; #查看test庫下面所有表
- show global variables like ‘port’; #查看MySQL端口號(hào)
- CREATE DATABASE guest CHARACTER SET utf8; #創(chuàng)建guest數(shù)據(jù)庫
書中使用如下代碼演示了如何通過pymysql庫對(duì)數(shù)據(jù)庫進(jìn)行操作,插入數(shù)據(jù),但是書中忽略了一個(gè)重要前提,我們從開始新建Django項(xiàng)目的時(shí)候,就使用的是SQLite3數(shù)據(jù)庫,并沒有用MySQL進(jìn)行過任何操作,這如果直接按代碼執(zhí)行,只會(huì)提示錯(cuò)誤沒有g(shù)uest表,對(duì)啊,是沒有啊,上面只是在基本操作里,新建了guest庫,但是沒有在guest庫下新建表,所以在執(zhí)行插入數(shù)據(jù)的代碼之前,我們應(yīng)該先新建兩個(gè)表:sign_event、sign_guest
# 創(chuàng)建sign_event表
CREATE TABLE `sign_event` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(100) NOT NULL,
`limit` integer,
`status` BOOLEAN,
`address` varchar(200) NOT NULL,
`start_time` DATETIME,
`create_time` DATETIME DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
)ENGINE=InnoDB DEFAULT CHARSET=utf8;
alter table `sign_event` add index id(id);
# 創(chuàng)建sign_guest表
CREATE TABLE `sign_guest` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`event_id` int(11) NOT NULL,
`realname` varchar(64) NOT NULL,
`phone` varchar(16) NOT NULL,
`email` varchar(254) NOT NULL,
`sign` BOOLEAN,
`create_time` DATETIME DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
FOREIGN KEY (`event_id`) REFERENCES sign_event(id)
)ENGINE=InnoDB DEFAULT CHARSET=utf8;
alter table `sign_guest` add index_id(id);
alter table `sign_guest` add unique(event_id, phone);
MySQL語法規(guī)則:
--在表中添加索引值
ALTER TABLE 表名字 ADD INDEX 索引名 (列名);
--在sign_guest表的id列上建立名為indx_id的索引
alter tablesign_guestadd index id(id);
#! /usr/bin python
# -*- coding: utf-8 -*-
from pymysql import cursors, connect
# 連接數(shù)據(jù)庫
conn = connect(host='127.0.0.1',
user='root',
password='nsfocus',
db='guest',
charset='utf8mb4',
cursorclass=cursors.DictCursor)
try:
with conn.cursor() as cursor:
# 創(chuàng)建發(fā)布會(huì)數(shù)據(jù)
sql = 'INSERT INTO sign_event (name, `limit`, status, address, start_time, create_time) VALUES ("紅米MAX發(fā)布會(huì)", 200, 1, "北京會(huì)展中心", "2016-09-22 14:00:00", NOW());'
cursor.execute(sql)
# 提交事務(wù)
conn.commit()
# 創(chuàng)建嘉賓數(shù)據(jù)
sql = 'INSERT INTO sign_guest (realname, phone, email, `sign`, event_id, create_time) VALUES ("Tom", 18800110002, "tom@mail.com", 0, 1, NOW());'
cursor.execute(sql)
# 提交事務(wù)
conn.commit()
with conn.cursor() as cursor:
# 查詢剛剛添加的嘉賓
sql = 'SELECT realname, phone, email, sign FROM sign_guest WHERE phone=%s'
cursor.execute(sql, ('18800110002',))
result = cursor.fetchone()
print result
finally:
conn.close()
在這個(gè)過程中遇到一些問題:
我們安裝了MySQL數(shù)據(jù)庫后,雖然創(chuàng)建了guest數(shù)據(jù)庫,但是并沒有創(chuàng)建發(fā)布會(huì)表、嘉賓表,所以如果按書中直接執(zhí)行此py文件,一定會(huì)報(bào)錯(cuò),提示guest表不存在?。。?/p>
如何解決這個(gè)問題,很簡(jiǎn)單,參考之前models.py文件里的設(shè)置,先創(chuàng)建好兩個(gè)數(shù)據(jù)表event、guest,再來執(zhí)行這個(gè)py文件就不會(huì)出錯(cuò)了!
引申出兩個(gè)問題:
- 如何使MySQL服務(wù)端不只是監(jiān)聽本地127.0.0.1這個(gè)地址?
- 這就需要修改配置文件/etc/mysql/mysql.conf.d/mysqld.cnf,將其中的bind-address由127.0.0.1修改為0.0.0.0,重啟MySQL服務(wù)即可/etc/init.d/mysql restart;
- 如果通過遠(yuǎn)程來訪問MySQL服務(wù)端?
- 對(duì)MySQL實(shí)在不熟,發(fā)現(xiàn)用起來很多基礎(chǔ)知識(shí)都不懂,查了好半天的資料才找到問題根本,原本以為在配置文件里修改各什么安全設(shè)置就能搞定,然而并不是這么回事,這是由于root用戶在mysql數(shù)據(jù)庫中存儲(chǔ)的host字段的限制;
- 首先在本地登錄MySQL數(shù)據(jù)庫:mysql -u root -p,然后切換至mysql數(shù)據(jù)庫:use mysql;,查看user表中root帳號(hào)的記錄:select * from user where user=’root’;,可以發(fā)現(xiàn)host字段的值為localhost,這就是為什么遠(yuǎn)程主機(jī)無法使用root帳號(hào)來訪問的原因了;
- 解決辦法就是給host字段增加遠(yuǎn)程主機(jī)的IP:grant all privileges on . to root@”遠(yuǎn)程主機(jī)IP地址” identified by “root帳號(hào)對(duì)應(yīng)的密碼”;,這就相當(dāng)于給遠(yuǎn)程IP賦予了所有的權(quán)限,包括遠(yuǎn)程訪問的權(quán)限,然后輸入:flush privileges;,這相當(dāng)于是重新加載一下mysql權(quán)限;
- 至此,就又可以從本地訪問也能從遠(yuǎn)程主機(jī)訪問了。
pymysql里的幾個(gè)重要函數(shù):
- connect():建立數(shù)據(jù)庫連接;
- cursor():獲取數(shù)據(jù)庫操作游標(biāo);
- execute():執(zhí)行SQL語句;
- commit():提交數(shù)據(jù)庫執(zhí)行;
- close():關(guān)閉數(shù)據(jù)庫連接;
在Django中配置MyDQL
修改配置文件/guest/settings.py:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'HOST': '127.0.0.1',
'PORT': '3306',
'NAME': 'guest',
'USER': 'root',
'PASSWORD': '123456',
'OPTIONS': {
'init_command': "SET sql_mode='STRICT_TRANS_TABLES'",
},
}
}
注意:需要先把原數(shù)據(jù)庫注釋掉。
蟲師的是在本章節(jié),才講解了如何將SQLite3里的數(shù)據(jù)同步至MySQL里,因?yàn)椴⒉荒苓@樣復(fù)制數(shù)據(jù),但是可以使用:
python manage.py migrate
命令來重新執(zhí)行數(shù)據(jù)庫同步,是數(shù)據(jù)模型重新在MySQL數(shù)據(jù)庫中生成表。這也就是上面我提到的蟲師缺少的部分,只不過我上面是用笨方法手工重建MySQL的數(shù)據(jù)表,而這里是使用數(shù)據(jù)同步命令。
但是在執(zhí)行此命令的時(shí)候也會(huì)遇到問題,即:“如何讓Django通過PyMySQL來連接數(shù)據(jù)庫”?
需要在/guest/init.py中加入如下代碼:
import pymysql
pymysql.install_as_MySQLdb()
再次執(zhí)行migrate命令就不會(huì)出錯(cuò)了,由于更換了MySQL數(shù)據(jù)庫,所以admin后臺(tái)的超級(jí)管理員的賬號(hào)也要重建。
MySQL管理工具
- Navicat
- SQLyog
至此第4章的全部?jī)?nèi)容都結(jié)束了。本章的內(nèi)容主要圍繞Django的Model層,也就是數(shù)據(jù)層做簡(jiǎn)要介紹。主要知識(shí)點(diǎn)就是model.py以及數(shù)據(jù)在管理后臺(tái)admin.py里如何展示。