如何强制Django使用服务名称连接到Oracle

时间:2013-10-08 11:34:09

标签: python sql django oracle

问:如何指定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',
    }
}

这很好用。

但是,当我用服务名称替换'NAME'时,如下

 '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中运行良好。

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

5 个答案:

答案 0 :(得分:14)

谢谢大家,有一个“文件化”的解决方案:

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

注意:HOST和PORT键需要不在字典中 - 否则Django会尝试连接完整的“NAME”作为SID。

答案 1 :(得分: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',
}

我已经使用SCON主机名对HOST进行了尝试,并验证了这一点。

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

答案 2 :(得分: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 docs):

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)

然后将NAME更改为SERVICE_NAME变量,将其更改为您的连接'default':

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

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

答案 3 :(得分:2)

我使用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',
    }
    
  3. 有关详细信息,请参阅Connecting Django to Oracle database using service name

答案 4 :(得分: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',
}

请勿在用户名和/或密码中输入以下任何字符:

@/(