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

发布于 2024-12-06 07:37:32 字数 1670 浏览 5 评论 0原文

我正在使用 django ORM 和 postgres 数据库。一小组用户使用导入和导出脚本与其进行交互。该数据库仅在我们的内网上可用。如果有人在 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 应用程序,因此是一个中间件解决方案 如何我要在 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)

这似乎可以解决问题。

I am using the django ORM with a postgres database. A small group of users interact with it using import and export scripts. The database is only available on our intranet. If someone tries to use the database when postgres is unavailable the scripts hang. I would like to make the scripts test whether the database is available before attempting to process any data.

I can connect to the database using the shell, import a model, and attempt to make a query:

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

this results in a long delay, but then django raises an OperationalError with an informative message ("could not connect to server: Network is unreachable...").

I thought to test database access by making a minimal query to the database, something like:

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

but this never progresses beyond the cursor = connection.cursor() line. No error message.

  • Why does one of these queries raise an error, but not the other?
  • What's the best way to test from a script whether the database is available?
  • How can I ensure that an error will be raised if the connection doesn't succeed within reasonable (perhaps user specified) time?

This is not a web application, so a middleware solution à la How do I test a database connection in Django? isn't possible.

Edit

Following @benjaoming's suggestion, I've made a function to test the connection:

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)

This seems to do the trick.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

吃颗糖壮壮胆 2024-12-13 07:37:33

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

You can use another method for finding out if the postgres server is reachable: For instance the socket module -- just do a socket.create_connection(("server", port)) and see what exceptions it raises...

沉默的熊 2024-12-13 07:37:33

使用多数据库路由 技巧是检查数据库在 django 初始化时是否可访问,然后将所有 ORM 查询路由到后备数据库。

检查数据库是否存在的一种方法是在 try .. except 块中运行 ORM 查询,并设置一个可在路由器中访问的变量.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 本身。

自定义路由器将检查变量是否已设置并路由到您的后备数据库

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

    # define db_for_write likewise

Using multiple database routing,

The trick is to check if the database is reachable at django init time, and then route all the ORM queries to your fallback db.

I one way of checking if the database exists or not is running an ORM query inside a try..except block and set a variable which is accessible in your 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

you could put this code in urls.py or the routers.py itself.

the custom router will check if the variable is set and route to your fallback 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
困倦 2024-12-13 07:37:33
from django.db import connections
db_conn = connections['default']
try:
    c = db_conn.cursor()
except Exception as e:
    connected = False
else:
    connected = True

这可用于检查与数据库的连接。

from django.db import connections
db_conn = connections['default']
try:
    c = db_conn.cursor()
except Exception as e:
    connected = False
else:
    connected = True

This can be used to check connections with databases.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文