2016-06-10 152 views
0


我是django webapp開發的新手,我遇到了一個問題。我創建了1個模型的應用程序,使用1個表單將數據插入數據庫。我將爲此使用多個數據庫。每個數據庫將有1個表(現在)具有相同的結構。現在我的問題是:

如何爲多個數據庫及其各自的表使用1個模型,1個視圖和1個窗體。數據庫和表格應該打開調用他們各自的URL。

例如http://www.example.com/x/abc/將訪問第一個數據庫,它是所有操作的表。
http://www.example.com/y/abc/將訪問第二個數據庫

我已經嘗試過django文檔中提供的示例數據庫路由,但它沒有多大幫助。我也找不到解決此特定問題的相對帖子/問題
django一個應用程序一個模型多個數據庫

我想這樣做,因爲稍後我將添加更多模型和表單以訪問數據庫表中的數據,這似乎是最簡潔的方式我

PS:我使用Django 1.9.6

+1

而且你必須有單獨的數據庫,因爲......?您是否考慮過使用URL路徑段作爲標識符的替代方法,並將該標識符用作外鍵來過濾數據? – Brandon

+0

,因爲它們裏面的表格將具有相同的結構,但具有不同的數據,現在的URL不是一個大問題。問題在於「1個模型,1個視圖和1個多個數據庫的表單」,以避免大量的重複。 – rrawat

+1

如果數據不同,它會有什麼不同?它都是通過外鍵分隔的。外鍵方法將您的複雜度降低了一個數量級。 – Brandon

回答

3

不管這是否是構建應用程序的一個很好的方式,你可以告訴Django閱讀和使用寫一個數據庫:

Person.objects.using('db1').create(...) 
Person.objects.using('db2').create(...) 

因此,您不需要使用路由器,只需在您的設置中定義兩個數據庫並在兩者上運行遷移即可。您的模型表將在每個數據庫中創建,並且在您的代碼中,您可以根據您選擇的任何邏輯(例如基於請求路徑)從兩個數據庫中讀取和寫入數據。

https://docs.djangoproject.com/en/1.9/topics/db/multi-db/#manually-selecting-a-database

+0

您還需要定義settings.py中的所有數據庫 - 目前您可能只定義了默認數據庫 – HenryM

+0

謝謝。我還閱讀了這種方法並將使用它。但我想知道是否有另一種解決方案。感謝您的幫助 – rrawat

1

我響應,因爲你的「我想知道是否有另一種解決方案」的評論的。有。我有它在網站上運行...多個SQLite數據庫與一個應用程序。你也提到了數據庫路由器問題,我也在努力。

首先,把任何地方router.py文件,該文件包含以下內容:

class Router(object): 

    appname = '' 

    def db_for_read(self, model, **hints): 
     """ 
     Attempts to read self.appname models go to model.db. 
     """ 
     if model._meta.app_label == self.appname: 
      return model.db 
     return None 

    def db_for_write(self, model, **hints): 
     """ 
     Attempts to write self.appname models go to model.db. 
     """ 
     if model._meta.app_label == self.appname: 
      return model.db 
     return None 

    def allow_relation(self, obj1, obj2, **hints): 
     """ 
     Allow relations if a model in the self.appname app is involved. 
     """ 
     if obj1._meta.app_label == self.appname or \ 
      obj2._meta.app_label == self.appname: 
      return True 
     return None 

    # This is possibly the new way, for beyond 1.8. 
    ''' 
    def allow_migrate(self, db, app_label, model_name=None, **hints): 
     """ 
     Make sure the self.appname app only appears in the self.appname 
     database. 
     """ 
     if app_label == self.appname: 
      return db == self.appname 
     return None 
    ''' 

    # Contrary to Djano docs this one works with 1.8, not the one above. 
    def allow_migrate(self, db, model): 
      """ 
      Make sure the self.appname app only appears in the self.appname 
      database. 
      """ 
      if db == self.appname: 
       return model._meta.app_label == self.appname 
      elif model._meta.app_label == self.appname: 
       return False 
      return None 

我只使用Django 1.8測試這一點;正如你使用1.9,根據文檔,至少必須使用其他allow_migrate

特別要注意的是:(1)沒有帶有屬性的Router()的squirously基類,這意味着Python type函數可以很容易地用來克隆它; (2)很明顯,當前模型實例可以通過外部命名空間在Router()內部訪問。

所以,現在,在你的models.py,這樣做:

from django.db import models 

import os 
appname = os.path.dirname(__file__).split('/')[-1] 
from dirwhereyouputtherouter.router import Router 
router = type(appname, (Router,), dict(appname=appname)) 

class Book(models.Model): 

    # This is the default, for use when there is only one db per app. 
    db = appname 

    # the various fields here, etc. 

做到這一點對每個模型。然後Router()當遇到任何查詢將return model.db。我在這裏選擇,在我的方案中,讓應用程序的默認Django方案從其目錄的名稱中獲取它的名稱。

現在,在settings.py中,您需要DATABASE_ROUTERS = [ 'appdir.models.router', ]。這指示通過使用type()函數在models.py中初始化的router查詢。特別要注意的是,我沒有在DATABASE_ROUTERS列出default數據庫。我確實有一個,它在DATABASES設置中列出,其中default爲關鍵。當您進行初始遷移時,各種Django應用程序表最終將在default數據庫中結束,當然,因爲Router()將退出。

因此,在您的視圖中,您將從Book.db = x開始,其中視圖簽名爲myview(request, x, someothername):。有一個機會,你可能想要在finally塊中使用try: finally:來填充整個視圖體,你可以將數據庫的選擇返回到某個默認值。

我必須承認,當涉及到遷移時,軟膏中可能會有蒼蠅。我討厭那些,在我的情況下,我會在我更新它們的時候寫下我的小SQLite數據庫的全部內容,這經常是這樣。所以,不用擔心保存數據,只要需要進行更改,我就會將它們和Migrations文件夾丟棄。但是如果你的情況不同,你可能不得不努力與migratemakemigrations命令。我的每個數據庫都具有相同的模式,由模型定義。所以我實際上首先創建了一個空白數據庫,臨時在DATABASES設置中輸入一個與應用程序名稱相同的條目。我用它創建SQLite數據庫文件的一個副本,然後只需複製它並在我想添加新數據庫時將其重命名(將新數據庫的詳細信息添加到DATABASES並刪除以appname作爲關鍵字的臨時條目)。或者,您可能希望保留並善用其DATABASES中的密鑰是應用程序名稱的數據庫。

但遺憾的是,我們沒有完成。我不得不修復admin.py。在admin.pyclass BookAdmin(admin.ModelAdmin):中創建之後,按照通常的方式,您將無法在管理員中找到您的兩個數據庫。所以我admin.py樣子:

from django.contrib import admin 
from django.conf import settings 
import os 

class BookAdmin(admin.ModelAdmin): 

    list_display = ... 
    list_filter = ... 
    etc. 

from models import Book 


appname = os.path.dirname(__file__).split('/')[-1] 

dbkeys = settings.DATABASES.keys() 
while 'default' in dbkeys: dbkeys.remove('default') 
dbkeys = [ k for k in dbkeys if os.path.dirname(settings.DATABASES[k]['NAME']).split(os.sep)[-1] == appname ] 

for dbname in dbkeys: 

    if dbname == dbkeys[0]: 

     class Book_(Book): 
      class Meta: 
       proxy = True 
       verbose_name = Book.__name__ + '_' + ''.join('_' + x.capitalize() or '_' for x in dbname.split('_')) 
       verbose_name_plural = Book.__name__ + 's_'+ ''.join('_' + x.capitalize() or '_' for x in dbname.split('_')) 
       db_table = appname + '_book' 
     Book_.db = dbname 
     Book_.__name__ = Book.__name__ + '_' + appname.capitalize() + '_' + ''.join('_' + x.capitalize() or '_' for x in dbname.split('_')) 
     admin.site.register(Book_, BookAdmin) 


    elif dbname == dbkeys[1]: 

     class Book__(Book): 
      class Meta: 
       proxy = True 
       verbose_name = Book.__name__ + '_' + ''.join('_' + x.capitalize() or '_' for x in dbname.split('_')) 
       verbose_name_plural = Book.__name__ + 's_'+ ''.join('_' + x.capitalize() or '_' for x in dbname.split('_')) 
       db_table = appname + '_book' 
     Book__.db = dbname 
     Book__.__name__ = Book.__name__ + '_' + appname.capitalize() + '_' + ''.join('_' + x.capitalize() or '_' for x in dbname.split('_')) 
     admin.site.register(Book__, BookAdmin) 

這工作,因爲我把數據庫文件在該應用程序的文件夾中的每個應用程序。對不起,這一切都有點棘手。我有很好的理由想要這個能力。另請參閱我未回答的有關子分類模型的問題,以便使用admin.site.registerhere進行註冊。

相關問題