27👍
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.
8👍
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)
- Django – inline – Search for existing record instead of adding a new one
- Error "Could not load Boto's S3 bindings."
- Sometimes request.session.session_key is None
4👍
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
- Validating a Django model field based on another field's value?
- Django: How to get the root path of a site in template?
- Are there problems developing Django on Jython?
- Quantize result has too many digits for current context
- Django admin, extending admin with custom views
3👍
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.
- Separating Django App Views
- Django admin dropdown of 1000s of users
- Issue trying to change language from Django template
- Django Multiple Databases Fallback to Master if Slave is down
0👍
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:
@/(