How to get django-ldapdb to recognize datasource as LDAP

Viewed 464

I have followed the directions in the django-ldap README and I cannot seem to get django-ldapdb to act like it's making an LDAP query. The following has been edited on a brand new instance of Django v.2.1.2 using with Python 3.7:

Changes to settings.py:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    },
    'ldap': {
        'ENGINE': 'ldapdb.backends.ldap',
        'NAME': 'ldaps://my.server',
        'USER': 'cn=some user',
        'PASSWORD': 'somePassword',
    }
}
DATABASE_ROUTERS = ['ldapdb.router.Router']

New models.py:

class MyPerson(ldapdb.models.Model):
        base_dn = "ou=people,dc=ucsf,dc=edu"
        object_classes = ['person', 'myPerson]

        uid = fields.IntegerField(db_column='uid')
        displayname = fields.CharField(db_column='displayname')
        eid = fields.CharField(db_column='eid')

        def __str__(self):
            return str(self.uid)

        def _unicode__(self):
            return str(self.uid)

The query in my view. First I tried:

result = MyPerson.objects.filter(uid=99894)

Then I tried:

result = MyPerson.objects.using('ldap').filter(uid=99894)

Running the Django dev server in PyCharm's debugger I can see that result receives a QuerySet with a message of:

Unable to get repr for <class 'django.db.models.query.QuerySet'>

What do I mean by "message". Honestly I'm not sure, but the debugger shows this:

enter image description here

Also, it seems that though the db member of the QuerySet is 'ldap', and the query member shows an SQL query, not an LDAP filter. As I traced the HTTP request through the URL routing, to the view, to the query, and then the result, I never once saw it make any sort of LDAP-related call. For good measure I mangled the LDAP bind password and I don't get a bind error. Pretty sure I'm missing something that lets Django know I want to work with LDAP at this point... I just don't know what that is.

1 Answers

As LDAPdoes not represent a relational database and generally has a schema which is created via configuration and not as it would be with queries, it never dawned on me that I needed to run manage.py makemigrations and manage.py migrate. (I'm relatively new to Python, and even more so to Django. Multi-datasource ORMs that I've used and extended for LDAP in the past did not required similar preparations.) On a hunch, I ran the manage.py commands over my LDAP models and then tried my code again. Now it works.

FWIW - I worked with PHP Symfony for some years and authored ucsf-iam/UcsfLdapOrm. While Symfony also has a db migration process, as LDAP schema are fairly static, when I wrote that LDAP ORM I hard coded part of what Django migration takes care of on the fly. The rest was taken care of by PHP annotations in model classes, similar to how Django has pythonic field types and relates them to LDAP attribute types. Now that I understand all of this better, I have a deeper appreciation for how Django does ORM setup.

I hope this is instructional for other LDAP developers moving over to Python and Django.

Related