从django测试postgres数据库可访问性

时间:2011-09-25 20:15:08

标签: django django-orm psycopg2

我正在使用django ORM和postgres数据库。一小组用户使用导入和导出脚本与其进行交互。该数据库仅在我们的Intranet上可用。如果有人在postgres不可用时尝试使用数据库,则脚本会挂起。在尝试处理任何数据之前,我想让脚本测试数据库是否可用。

我可以使用shell连接到数据库,导入模型,并尝试进行查询:

from myapp.models import mymodel
mymodel.objects.count()

这导致了很长的延迟,但是随后django引发了一个带有信息性消息的OperationalError(“无法连接到服务器:网络无法访问......”)。

我想通过对数据库进行最小化查询来测试数据库访问,例如:

from django.db import connection
cursor = connection.cursor()
cursor.execute("select 1")

但这永远不会超越cursor = connection.cursor()行。没有错误消息。

  • 为什么其中一个查询会引发错误,而不是另一个?
  • 从脚本测试数据库是否可用的最佳方法是什么?
  • 如果连接在合理(可能是用户指定的)时间内没有成功,我如何确保会出现错误?

这不是一个Web应用程序,因此无法使用la How do I test a database connection in Django?中间件解决方案。

修改

按照@ benjaoming的建议,我做了一个测试连接的功能:

import socket

def test_connection():
    """Test whether the postgres database is available. Usage:

        if "--offline" in sys.argv:
            os.environ['DJANGO_SETTINGS_MODULE'] = 'myapp.settings.offline'
        else:
            os.environ['DJANGO_SETTINGS_MODULE'] = 'myapp.settings.standard'
            from myapp.functions.connection import test_connection
            test_connection()
    """
    try:
        s = socket.create_connection(("example.net", 5432), 5)
        s.close()
    except socket.timeout:
        msg = """Can't detect the postgres server. If you're outside the
        intranet, you might need to turn the VPN on."""
        raise socket.timeout(msg)

这似乎可以解决问题。

2 个答案:

答案 0 :(得分:3)

您可以使用另一种方法来查明postgres服务器是否可访问:例如套接字模块 - 只需执行socket.create_connection((“server”,port))并查看它引发的异常... < / p>

答案 1 :(得分:3)

使用multiple database routing

诀窍是检查django初始化时是否可以访问数据库,然后route查询到回退数据库的所有ORM查询。

我检查数据库是否存在的一种方法是在try .. except块内运行ORM查询并设置一个可在routers.py中访问的变量

from django.db import connections
conn = connections['default']
try:
    c = conn.cursor() #this will take some time if error
except OperationalError:
    reachable = False
else:
    reachable = True

您可以将此代码放在urls.pyrouters.py本身。

自定义路由器将检查变量是否已设置并路由到回退db

class AppRouter(object):
    def db_for_read(self, model, **hints):
       if reachable :
           return 'actual_db'
       else:
           return 'fallback_db'

    # define db_for_write likewise