Reputation: 1811
Q : How do specify that Django needs to connect to Oracle DB using the service name and not SID ?
Hi,
I am currently telling my Django configuration to connect to Oracle using my SID.
However, I'll need to connect using the service name and not the SID.
APP_DATABASES={
'default': {
'ENGINE': 'django.db.backends.oracle',
'NAME': 'myservice',
'USER': 'system',
'PASSWORD': 'admin123',
'HOST': '192.168.1.45',
'PORT': '1699',
}
}
This works fine.
However, When I replace the 'NAME' with the service name as follows
'default': {
'ENGINE': 'django.db.backends.oracle',
'NAME': 'myservice.bose.com',
'USER': 'system',
'PASSWORD': 'admin123',
'HOST': '192.168.1.45',
'PORT': '1699',
}
I get a
ORA-12505: TNS:listener does not currently know of SID given in connect descriptor
Clearly Django is telling Oracle to connect using the SID which is not what I want Django to do.
How do specify that Django needs to connect to Oracle DB using the service and not SID ?
Note : I've tested that the service name mentioned above. It works great from Oracle SQL Developer.
Thanks - would really appreciate leads.
Upvotes: 13
Views: 18463
Reputation: 3328
Here is the way that works:
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',
}
Don't put any of the following characters into user name and/or password:
@/(
Upvotes: 0
Reputation: 41
I use tnsnames.ora. It works for me on Django 1.7. These are the steps:
Add an entry in tnsnames.ora for the connection.
myservice =
(DESCRIPTION =
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.1.45)(PORT = 1699))
)
(CONNECT_DATA =
(SERVICE_NAME = myservice.bose.com)
)
)
Change Django database settings to
'default': {
'ENGINE': 'django.db.backends.oracle',
'NAME': 'myservice',
'USER': 'system',
'PASSWORD': 'admin123',
}
For details, please refer to Connecting Django to Oracle database using service name
Upvotes: 4
Reputation: 1811
Thanks guys, There's a "documented" solution to this:
'default': {
'ENGINE': 'django.db.backends.oracle',
'NAME': 'host.db.com:1699/oracle_service.db.com',
'USER': 'user',
'PASSWORD': 'pass',
}
Note: The HOST and PORT keys need to be left out of the dictionary - else Django will try connecting with the complete "NAME" as an SID.
Upvotes: 27
Reputation: 181
Looking at the code that nickzam pasted:
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)
.. it is clear that if you do not specify a 'PORT' parameter, the 'NAME' parameter is used 'as is'. Therefore, passing an Oracle connect string as the 'NAME' parameter will do the trick (if you remove the 'PORT' parameter).
Basically something like this will work:
'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',
}
I have tried this using a SCAN hostname for HOST and verified that this works too.
WARNING: My tests so far have been limited to checking whether the connect string is accepted, a connection is made and my app is served successfully, accessing data. Before relying on this configuration I would advise more aggressive testing 8)
Upvotes: 8
Reputation: 813
Behind the scenes Django uses cx_Oracle library to connect to Oracle database. Source: 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)
Function cx_Oracle.make_dsn() supports optional parameter service_name (excerpt from 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.
Unfortunately, Django is not passing service_name
parameter on connection.
If you really need it, add feature request to Django or patch your local version of Django to support SERVICE_NAME parameter (bad idea, you will need to support it by yourself):
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)
Then change NAME
to SERVICE_NAME
variable to your connection 'default':
'default': {
'ENGINE': 'django.db.backends.oracle',
'SERVICE_NAME': 'myservice.bose.com',
'USER': 'system',
'PASSWORD': 'admin123',
'HOST': '192.168.1.45',
'PORT': '1699',
}
Later, I am going to add it as a pull request to Django source.
Upvotes: 3