12

问:如何指定 Django 需要使用服务名称而不是 SID 连接到 Oracle DB?

你好,

我目前正在告诉我的 Django 配置使用我的 SID 连接到 Oracle。

但是,我需要使用服务名称而不是 SID 进行连接。

APP_DATABASES={
    'default': {
            'ENGINE': 'django.db.backends.oracle',
            'NAME': 'myservice',
            'USER': 'system',
            'PASSWORD': 'admin123',
            'HOST': '192.168.1.45',
            'PORT': '1699',
    }
}

这工作正常。

但是,当我将“名称”替换为服务名称时,如下所示

 'default': {
                'ENGINE': 'django.db.backends.oracle',
                'NAME': 'myservice.bose.com',
                'USER': 'system',
                'PASSWORD': 'admin123',
                'HOST': '192.168.1.45',
                'PORT': '1699',
        }

我得到一个

ORA-12505: TNS:listener does not currently know of SID given in connect descriptor

显然 Django 告诉 Oracle 使用 SID 进行连接,这不是我想要 Django 做的。

如何指定 Django 需要使用服务而不是 SID 连接到 Oracle DB?

注意:我已经测试了上面提到的服务名称。它在 Oracle SQL Developer 中运行良好。

谢谢 - 非常感谢潜在客户。

4

5 回答 5

24

谢谢大家,有一个“记录在案”的解决方案:

        'default': {
                'ENGINE': 'django.db.backends.oracle',
                'NAME': 'host.db.com:1699/oracle_service.db.com',
                'USER': 'user',
                'PASSWORD': 'pass',
        }

注意:HOST 和 PORT 键需要从字典中排除 - 否则 Django 将尝试使用完整的“NAME”作为 SID 进行连接。

于 2013-12-10T05:24:28.480 回答
7

查看 nickzam 粘贴的代码:

import cx_Oracle as Database

def _connect_string(self):
    settings_dict = self.settings_dict
    if not settings_dict['HOST'].strip():
        settings_dict['HOST'] = 'localhost'
    if settings_dict['PORT'].strip():
        dsn = Database.makedsn(settings_dict['HOST'],
                               int(settings_dict['PORT']),
                               settings_dict['NAME'])
    else:
        dsn = settings_dict['NAME']
    return "%s/%s@%s" % (settings_dict['USER'],
                         settings_dict['PASSWORD'], dsn)

.. 很明显,如果您不指定“PORT”参数,则“NAME”参数将“按原样”使用。因此,将 Oracle 连接字符串作为 'NAME' 参数传递就可以解决问题(如果您删除了 'PORT' 参数)。

基本上这样的事情会起作用:

'default': {
    'ENGINE': 'oraclepool',
    'NAME': '(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=mydbhostname.example.com)(PORT=1521)))(CONNECT_DATA=(SERVICE_NAME=myservicename.example.com)))',
    'USER': 'scott',
    'PASSWORD': 'tiger',
}

我已经尝试使用 SCAN 主机名作为 HOST 并验证这也有效。

警告:到目前为止,我的测试仅限于检查连接字符串是否被接受、连接是否建立以及我的应用程序是否成功服务、访问数据。在依赖此配置之前,我建议进行更积极的测试 8)

于 2013-11-05T16:35:46.583 回答
3

在幕后 Django 使用 cx_Oracle 库连接到 Oracle 数据库。来源:https ://github.com/django/django/blob/master/django/db/backends/oracle/base.py

import cx_Oracle as Database

def _connect_string(self):
        settings_dict = self.settings_dict
        if not settings_dict['HOST'].strip():
            settings_dict['HOST'] = 'localhost'
        if settings_dict['PORT'].strip():
            dsn = Database.makedsn(settings_dict['HOST'],
                                   int(settings_dict['PORT']),
                                   settings_dict['NAME'])
        else:
            dsn = settings_dict['NAME']
        return "%s/%s@%s" % (settings_dict['USER'],
                             settings_dict['PASSWORD'], dsn)

函数 cx_Oracle.make_dsn() 支持可选参数 service_name(摘自 cx_Oracle 文档):

cx_Oracle.makedsn(host, port, sid[, service_name])

Return a string suitable for use as the dsn for the connect() method. This string is identical to the strings that are defined by the Oracle names server or defined in the tnsnames.ora file. If you wish to use the service name instead of the sid, do not include a value for the parameter sid and use the keyword parameter service_name instead. Note This method is an extension to the DB API definition.

不幸的是,Django 没有service_name在连接上传递参数。

如果你真的需要它,向 Django 添加功能请求或修补你的本地版本的 Django 以支持 SERVICE_NAME 参数(坏主意,你需要自己支持它):

def _connect_string(self):
    settings_dict = self.settings_dict
    if not settings_dict['HOST'].strip():
        settings_dict['HOST'] = 'localhost'
    if settings_dict['PORT'].strip():
        if not 'SERVICE_NAME' in settings_dict:
            dsn = Database.makedsn(settings_dict['HOST'],
                                   int(settings_dict['PORT']),
                                   settings_dict['NAME'])
        else:
            dsn = Database.makedsn(host=settings_dict['HOST'],
                                   port=int(settings_dict['PORT']),
                                   service_name=settings_dict['SERVICE_NAME'].strip())

    else:
        dsn = settings_dict['NAME']
    return "%s/%s@%s" % (settings_dict['USER'],
                         settings_dict['PASSWORD'], dsn)

然后将变量更改NAMESERVICE_NAME您的连接“默认”:

 'default': {
            'ENGINE': 'django.db.backends.oracle',
            'SERVICE_NAME': 'myservice.bose.com',
            'USER': 'system',
            'PASSWORD': 'admin123',
            'HOST': '192.168.1.45',
            'PORT': '1699',
    }

稍后,我将把它作为拉取请求添加到 Django 源。

于 2013-10-08T12:26:05.147 回答
3

我使用 tnsnames.ora。它适用于 Django 1.7。这些是步骤:

  1. 在 tnsnames.ora 中为连接添加一个条目。

    myservice =
     (DESCRIPTION = 
       (ADDRESS_LIST =
         (ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.1.45)(PORT = 1699))
       )
     (CONNECT_DATA =
       (SERVICE_NAME = myservice.bose.com)
     )
    )
    
  2. 将 Django 数据库设置更改为

    'default': {
      'ENGINE': 'django.db.backends.oracle',
      'NAME': 'myservice',
      'USER': 'system',
      'PASSWORD': 'admin123',
    }
    

详情请参考使用服务名连接 Django 到 Oracle 数据库

于 2015-02-12T02:41:34.067 回答
0

这是有效的方式:

myservice =
 (DESCRIPTION = 
   (ADDRESS_LIST =
     (ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.1.45)(PORT = 1699))
   )
 (CONNECT_DATA =
   (SERVICE_NAME = myservice_name)
 )
)

myservice = ''.join(trc_scan.split())

'default': {
  'ENGINE': 'django.db.backends.oracle',
  'NAME': myservice,
  'USER': 'someuser',
  'PASSWORD': 'somepsw',
}

不要将以下任何字符放入用户名和/或密码中:

@/(

于 2020-03-10T19:24:28.080 回答