2016-06-10 93 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进行注册。

相关问题