1. 程式人生 > >Django操作已有資料庫的資料

Django操作已有資料庫的資料

Django整合已有的資料庫和應用:Django最適合於所謂的green-field開發,即從頭開始的一個專案,正如你在一塊還長著青草的未開墾的土地上從零開始建造一棟建築一般。

然而,儘管Django偏愛從頭開始的專案,將這個框架和以前遺留的資料庫和應用相整合仍然是可能的。本章就將介紹一些整合的技巧。

與遺留資料庫整合

Django的資料庫層從Python程式碼生成SQL schemas—但是對於遺留資料庫,你已經擁有SQL schemas,這種情況下你需要為你已經存在的資料庫表寫模型(由於效能的原因,Django的資料庫層不支援通過執行時自省資料庫的不工作的物件-關係對映,為了使用資料庫API,你需要寫模型程式碼),幸運的是,Django帶有通過

閱讀你的資料庫表規劃來生成模型程式碼的輔助工具該輔助工具稱為manage.py inspectdb

使用inspectdb

The inspectdb工具內省檢查你的配置檔案(setting file)指向的資料庫,針對你的每一個表生成一個Django model的表現,然後將這些Python model的程式碼顯示在系統的標準輸出裡面。

下面是一個從頭開始的針對一個典型的遺留資料庫的整合過程

通過執行django-admin.py startproject mysite (這裡mysite是你的專案的名字)建立一個Django專案。好的,那我們在這個例子中就用這個mysite作為專案的名字。

編輯專案中的配置檔案, mysite/settings.py,告訴Django你的資料庫連線引數和資料庫名。具體的說,要提供DATABASE_NAME,DATABASE_ENGINE,DATABASE_USER,DATABASE_PASSWORD,DATABASE_HOST,和DATABASE_PORT這些配置資訊.

通過執行pythonmysite/manage.pystartappmyapp(這裡myapp是你的應用的名字)建立一個Django應用.那麼,我們就以myapp做為這個應用的名字.

執行命令pythonmysite/manage.pyinspectdb.這將在DATABASE_NAME資料庫中檢查所有的表和打印出為每張表生成的model class.看一看輸出結果想一下inspectdb能做些什麼.

將標準shell的輸出重定向,儲存輸出到你的應用的models.py檔案裡:

python mysite/manage.py inspectdb > mysite/myapp/models.py

編輯mysite/myapp/models.py檔案以清理生成的 models以及一些必要的定製化。下一個章節對此有些好的建議。

清理生成的Models

如你可能會預料到的,資料庫自省不是完美的,你需要對產生的模型程式碼做些許清理。這裡提醒一點關於處理生成 models的要點:

資料庫的每一個表都會被轉化為一個model類 (也就是說,資料庫的表和model的類之間做一對一的對映)。這意味著你需要為多對多連線的表,重構其models為ManyToManyField的物件。

所生成的每一個model中的每個欄位都擁有自己的屬性,包括id主鍵欄位。但是,請注意,如果某個model沒有主鍵的話,那麼Django會自動為其增加一個Id主鍵欄位。這樣一來,你也許希望使用如下程式碼來對任意行執行刪除操作:

id = models.IntegerField(primary_key=True)

這樣做並不是僅僅因為這些行是冗餘的,而且如果當你的應用需要向這些表中增加新記錄時,這些行會導致某些問題。而inspectdb命令並不能檢測出一個欄位是否自增長的,因此必要的時候,你必須將他們修改為AutoField.

每一個欄位型別,如CharField、DateField,是通過查詢資料庫列型別如VARCHAR,DATE來確定的。如果inspectdb無法對某個model欄位型別根據資料庫列型別進行對映,那麼它會使用TextField欄位進行代替,並且會在所生成model欄位後面加入Python註釋“該欄位型別是猜的”。因此,請特別注意這一點,並且在必要的時候相應的修改這些欄位型別。

如果你的資料庫中的某個欄位在Django中找不到合適的對應物,你可以放心的略過它,因為Django層並沒有要求必須包含你的表中的每一個欄位。

如果資料庫中某個列的名字是Python的保留字,比如pass、class或者for等,inspectdb會在每個屬性名後附加上_field,並將db_column屬性設定為真實的欄位名,比如pass,class或者for等。

例如,某張表中包含一個INT型別的列,其列名為for,那麼所生成的model將會包含如下所示的一個欄位:

for_field = models.IntegerField(db_column='for')

inspectdb會在該欄位後加注‘欄位重新命名,因為它是一個Python保留字’。

如果資料庫中某張表引用了其他表(正如大多數資料庫系統所做的那樣),你需要適當的修改所生成model的順序,以使得這種引用能夠正確對映。例如,model Book擁有一個針對於model Author的外來鍵,那麼後者應該先於前者被定義。如果你需要為一個還沒有被定義的model建立一個關係,那麼你可以使用該model的名字,而不是model物件本身。

對於PostgreSQL,MySQL和SQLite資料庫系統,inspectdb能夠自動檢測出主鍵關係。也就是說,它會在合適的位置插入primary_key=True。而對於其他資料庫系統,你必須為每一個model中至少一個欄位插入這樣的語句,因為Django的model要求必須擁有一個primary_key=True的欄位。

外來鍵檢測僅對PostgreSQL,還有MySQL表中的某些特定型別生效。至於其他資料庫,外來鍵欄位都將在假定其為INT列的情況下被自動生成為IntegerField。

與認證系統的整合

將Django與其他現有認證系統的使用者名稱和密碼或者認證方法進行整合是可以辦到的。

例如,你所在的公司也許已經安裝了LDAP,並且為每一個員工都儲存了相應的使用者名稱和密碼。如果使用者在LDAP和基於Django的應用上擁有獨立的賬號,那麼這時無論對於網路管理員還是使用者自己來說,都是一件很令人頭痛的事兒。

為了解決這樣的問題,Django認證系統能讓您以外掛方式與其他認證資源進行互動。您可以覆蓋Diangos的預設基於資料庫模式,您還可以使用預設的系統與其他系統進行互動。

指定認證後臺

在後臺,Django維護了一個用於檢查認證的後臺列表。當某個人呼叫django.contrib.auth.authenticate()(如12章中所述)時,Django會嘗試對其認證後臺進行遍歷認證。如果第一個認證方法失敗,Django會嘗試認證第二個,以此類推,一直到嘗試完全部。

認證後臺列表在AUTHENTICATION_BACKENDS設定中進行指定,它應該是指向知道如何認證的Python類的Python路徑的名字陣列,這些類可以放置在您的Python路徑的任何位置上。

預設情況下,AUTHENTICATION_BACKENDS被設定為如下:

('django.contrib.auth.backends.ModelBackend',)

那就是檢測Django使用者資料庫的基本認證模式。

對於多個順序組合的AUTHENTICATION_BACKENDS,如果其使用者名稱和密碼在多個後臺中都是有效的,那麼Django將會在第一個正確通過認證後停止進一步的處理。

如何寫一個認證後臺

一個認證後臺其實就是一個實現瞭如下兩個方法的類:get_user(id)和authenticate(**credentials)。

方法get_user需要一個引數id,這個id可以是使用者名稱,資料庫ID或者其他任何數值,該方法會返回一個User物件。

方法authenticate使用證書作為關鍵引數。大多數情況下,該方法看起來如下:

?
1 2 3 4 5 class MyBackend(object): def authenticate(self, username=None, password=None): # Check the username/password and return a User.

但是有時候它也可以認證某個令牌,例如:

?
1 2 3 4 5 class MyBackend(object): def authenticate(self, token=None): # Check the token and return a User.

每一個方法中,authenticate都應該檢測它所獲取的證書,並且當證書有效時,返回一個匹配於該證書的User物件,如果證書無效那麼返回None。

如Django會話、使用者和註冊中所述,Django管理系統緊密連線於其自己後臺資料庫的User物件。實現這個功能的最好辦法就是為您的後臺資料庫(如LDAP目錄,外部SQL資料庫等)中的每個使用者都建立一個對應的Django User物件。您可以提前寫一個指令碼來完成這個工作,也可以在某個使用者第一次登陸的時候在authenticate方法中進行實現。

以下是一個示例後臺程式,該後臺用於認證定義在setting.py檔案中的username和password變數,並且在該使用者第一次認證的時候建立一個相應的DjangoUser物件。

?
1 2 3 4 5 6 7 8 9 10 11 12 13