首頁  >  文章  >  後端開發  >  Django整合已有的資料庫與應用

Django整合已有的資料庫與應用

黄舟
黄舟原創
2017-01-17 14:01:041345瀏覽

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是你的專案的名字。好的,那我們在這個範例中就用這個mysite當專案的名字。


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


米透過執行一個運行的名稱「 ,我們就以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 settings
from django.contrib.auth.models import User, check_password
class 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 = True
user.is_superuser = True
user.save()
return user
return None
def 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-program
PythonHandler django.core.handlers.modpython
SetEnv DJANGO_SETTINGS_MODULE mysite.settings
PythonDebug On
</Location>

这里, a18e6dc59b27f1dbd64eaa88f15b0c14这一行表示用Django处理每个以根开头的URL.


精妙之处在于Django将9d68f4d645dd62cd4e002580b75a8b85指令值限定于一个特定的目录树上。举个例子,比如说您有一个在某个域中驱动大多数页面的遗留PHP应用,并且您希望不中断PHP代码的运行而在../admin/位置安装一个Django域。要做到这一点,您只需将9d68f4d645dd62cd4e002580b75a8b85值设置为/admin/即可。

<Location "/admin/">
SetHandler python-program
PythonHandler django.core.handlers.modpython
SetEnv DJANGO_SETTINGS_MODULE mysite.settings
PythonDebug On
</Location>

有了这样的设置,只有那些以/admin/开头的URL地址才会触发Django去进行处理,而任何其他页面依旧按之前已经存在的那些设置进行处理。


请注意,让Diango去处理那些合格的URL(比如在本章例子中的/admin/)并不会影响其对URL的解析。绝对路径对Django才是有效的(例如/admin/people/person/add/),而非去掉/admin/后的那部分URL(例如``/people/person/add/)。这意味着您的根URLconf必须包含居前的/admin/。

以上就是Django集成已有的数据库和应用的内容,更多相关内容请关注PHP中文网(www.php.cn)!


陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn