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使用認證作為關鍵參數。大多數情況下,該方法看起來如下:
class MyBackend(object):def authenticate(self, username=None, password=None):# Check the username/password and return a User.
但是有時候它也可以認證某個令牌,例如:
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對象。
from django.conf import settingsfrom django.contrib.auth.models import User, check_passwordclass SettingsBackend(object):"""Authenticate against the settings ADMIN_LOGIN and ADMIN_PASSWORD.Use the login name, and a hash of the password. For example:ADMIN_LOGIN = 'admin'ADMIN_PASSWORD = 'sha1$4e987$afbcf42e21bd417fb71db8c66b321e9fc33051de'"""def authenticate(self, username=None, password=None):login_valid = (settings.ADMIN_LOGIN == username)pwd_valid = check_password(password, settings.ADMIN_PASSWORD)if login_valid and pwd_valid:try:user = User.objects.get(username=username)except User.DoesNotExist:# Create a new user. Note that we can set password# to anything, because it won't be checked; the password# from settings.py will.user = User(username=username, password='get from settings.py')user.is_staff = Trueuser.is_superuser = Trueuser.save()return userreturn Nonedef get_user(self, user_id):try:return User.objects.get(pk=user_id)except User.DoesNotExist:
return None和遺留Web應用整合
同由其他技術驅動的應用一樣,在相同的Web伺服器上運行Django應用也是可行的。最簡單直接的辦法就是利用Apaches設定檔httpd.conf,將不同的URL類型代理至不同的技術。
關鍵在於只有在您的httpd.conf檔案中進行了相關定義,Django對某個特定的URL類型的驅動才會被啟用。在第20章中解釋的預設部署方案假定您需要Django去驅動某個特定域上的每一個頁面。
<Location "/">SetHandler python-programPythonHandler django.core.handlers.modpythonSetEnv DJANGO_SETTINGS_MODULE mysite.settingsPythonDebug On</Location>
這裡, <Location"/">這一行表示用Django處理每個以根開頭的URL.
精妙之處在於Django將<location>指令值限定於一個特定的分類樹上。舉個例子,比如說您有一個在某個域中驅動大多數頁面的遺留PHP應用,並且您希望不中斷PHP代碼的運行而在../admin/位置安裝一個Django域。要做到這一點,您只需將<location>值設定為/admin/即可。
<Location "/admin/">SetHandler python-programPythonHandler django.core.handlers.modpythonSetEnv DJANGO_SETTINGS_MODULE mysite.settingsPythonDebug On</Location>
有了這樣的設定,只有那些以/admin/開頭的URL地址才會觸發Django去進行處理,而任何其他頁面依舊按之前已經存在的那些設定進行處理。
請注意,讓Diango去處理那些合格的URL(比如在本章例子中的/admin/)並不會影響其對URL的解析。絕對路徑對Django才是有效(例如/admin/people/person/add/),而非去掉/admin/後的那部分URL(例如``/people/person/add/)。這意味著您的根URLconf必須包含居前的/admin/。
以上就是Django整合已有的資料庫和應用的內容,更多相關內容請關注topic.alibabacloud.com(www.php.cn)!