2

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.

lofidevops
  • 15,528
  • 14
  • 79
  • 119
JasonGabler
  • 570
  • 5
  • 9
  • you are getting the repr error probably because your __str__ method should return a string: `def __str__(self): return str(self.uid)` – Uku Loskit Nov 14 '18 at 00:01
  • @UkuLoskit , thank you for the suggestion but it made no difference. I understand that the uid member is an integer variabe and users of __str__ are expecting a string. That should be corrected either way. But, what made you think of that in relation to my problem? (btw, changing my original code above to reflect this change) – JasonGabler Nov 14 '18 at 00:17

1 Answers1

2

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.

JasonGabler
  • 570
  • 5
  • 9