Django 1.6 管理站点使用默认数据库

4 投票
1 回答
586 浏览
提问于 2025-04-29 20:05

我有一个项目,里面有几个应用,每个应用都有自己的数据库。我有一个可以正常工作的 routers.py 文件,用来指定每个模型应该使用哪个数据库。其中一个应用使用 django-admin 子站点来管理它的模型。

在 Django 1.5 的时候这一切都运作得很好,但当我升级到 Django 1.6 后,我无法再编辑我的模型了:当我访问某个模型的 edit 页面时,出现了一个错误 "[SQL Server Native Client 11.0]Login timeout expired"。

经过一些调查,似乎 Django 尝试连接到一个名为 default 的数据库,而这个数据库在我的项目中只包含一些虚假的数据,实际上不应该被使用。

为什么在 Django 1.6 中,Django 会尝试连接到 default 数据库,而在 1.5 中却没有这个问题呢?我该如何在 1.6 中解决这个问题?

[编辑]

经过进一步的研究,我发现 Django 在它的 ModelAdmin 类的一些函数中使用了 @transaction.atomic 装饰器。

查看这个装饰器的代码,似乎它是为了支持指定需要用于这个原子事务的数据库别名,使用 @transaction.atomic(using),而如果只是用 @transaction.atomic 这样调用,就会使用 django.db.utils 中定义的 DEFAULT_DB_ALIAS

我尝试过但没有成功地覆盖这种行为,想让这些函数使用我想要的数据库别名。

你知道有什么办法可以做到这一点吗?

暂无标签

1 个回答

0

我终于找到了一种方法,可以强制Django的管理后台使用我想要的数据库,但这个方法有点黑科技。如果有人有更好的解决方案,请一定分享出来。

我创建了一个名为admin_helper.py的文件,在里面重新定义了Django代码中使用@transaction.atomic这个装饰器的方法,内容完全一样,只是把装饰器改成了@transaction.atomic(DATABASE_ALIAS),这样就告诉Django使用正确的数据库:

DATABASE_ALIAS = 'alias_of_the_database_i_want_to_use'

class ModelAdminCustom(admin.ModelAdmin):
    @csrf_protect_m
    @transaction.atomic(DATABASE_ALIAS)
    def add_view(self, request, form_url='', extra_context=None):
        # exact same content as the method defined in django.contrib.admin.options.ModelAdmin

    @csrf_protect_m
    @transaction.atomic(DATABASE_ALIAS)
    def change_view(self, request, object_id, form_url='', extra_context=None):
        # exact same content as the method defined in django.contrib.admin.options.ModelAdmin

    @csrf_protect_m
    @transaction.atomic(DATABASE_ALIAS)
    def delete_view(self, request, object_id, extra_context=None):
        # exact same content as the method defined in django.contrib.admin.options.ModelAdmin

class MultiDBUserAdmin(UserAdmin):
    @sensitive_post_parameters_m
    @csrf_protect_m
    @transaction.atomic(DATABASE_ALIAS)
    def add_view(self, request, form_url='', extra_context=None):
        # exact same content as the method defined in django.contrib.auth.admin.UserAdmin

# Unregister existing instance of UserAdmin for the User model, and register my own
try:
    admin.site.unregister(User)
finally:
    admin.site.register(User, MultiDBUserAdmin)

然后在我的正常admin.py文件中:

from myapp.admin_helper import ModelAdminCustom

class MyModelAdmin(ModelAdminCustom):
    pass

admin.site.register(MyModel, MyModelAdmin)

撰写回答