Search and pagination¶
Searching is one of the most common LDAP operations. It allows clients to retrieve directory entries matching specific criteria, optionally returning only selected attributes. This section demonstrates a variety of search techniques and server-side features for controlling result sets.
The examples below cover:
Basic searches – retrieving entries and attributes within a specified subtree or scope.
Iterative searches – streaming results as they arrive.
Specialized searches – retrieving only the distinguished names, single attributes, or asserting result uniqueness.
Pagination – splitting large result sets into manageable chunks using either the Simple Paged Results control or the Virtual List View control.
Sorting – requesting server-side ordering of results.
Existence checks – quickly verifying whether an entry exists.
Error handling – dealing with missing search bases or other exceptional conditions.
These techniques can be combined to efficiently retrieve exactly the data you need from large or complex directory structures.
Search and receive objects and attributes¶
search_base = 'dc=freeiam,dc=org'
# search for DN and attrs
for entry in await conn.search(
search_base, Scope.SUBTREE, '(&(uid=*)(objectClass=person))'
):
print(entry.dn, entry.attr)
Search iterative¶
# search iterative for DN and attrs
async for entry in conn.search_iter(
search_base, Scope.SUBTREE, '(&(uid=*)(objectClass=person))'
):
print(entry.dn, entry.attr)
Search for DN only¶
# search for DN
async for entry in conn.search_dn(
search_base, Scope.SUBTREE, '(&(uid=*)(objectClass=person))'
):
print(entry.dn)
Paginated search using SimplePagedResult¶
# search paginated via SimplePagedResult
async for entry in conn.search_paged(
search_base,
Scope.Subtree,
'(&(uid=*)(objectClass=person))',
page_size=10,
):
print(entry.dn, entry.attr, entry.page)
Server-Side Sort search¶
# all of the previous searches allow specifying the ServerSideSorting control:
for entry in await conn.search(
search_base,
Scope.SUBTREE,
'(&(uid=*)(objectClass=person))',
sorting=[('uid', 'caseIgnoreOrderingMatch', False)],
):
print(entry.dn, entry.attr)
Paginated search using Virtual List View¶
# search paginated via VirtualListView + ServerSideSorting
async for entry in conn.search_paginated(
search_base,
Scope.Subtree,
'(&(uid=*)(objectClass=person))',
page_size=10,
sorting=[('uid', 'caseIgnoreOrderingMatch', False)],
):
print(entry.dn, entry.attr, entry.page)
Get single object¶
# get a certain object, and use its attributes
obj = await conn.get('uid=max.mustermann,dc=freeiam,dc=org')
print(obj.dn, obj.attr)
print(obj.attr['cn'])
print(obj.attr['CN']) # yes, attribute names are case sensitive!
print(obj.attr['commonName']) # and there are even aliases!!!
Get single attribute of certain object¶
# get a attribute of an object (even by alias!)
cn = await conn.get_attr('uid=max.mustermann,dc=freeiam,dc=org', 'commonName')
print(cn)
Search for unique results¶
# find unique entry
try:
(_entry,) = await conn.search(
search_base,
Scope.SUBTREE,
'(&(uid=max.mustermann)(objectClass=person))',
unique=True,
)
... # do something, ensured to be only the unique entry
except errors.NotUnique as exc:
# otherwise we have this error here, containg all search results
print('Bad member in', exc.results)
Check for entry existance¶
# or if you just need to know whether a object exists
await conn.exists('uid=max.mustermann,dc=freeiam,dc=org')
Error handling¶
# don't forget to handle errors for not existing objects
try:
await conn.get('uid=max.mustermann,dc=freeiam,dc=org')
except errors.NoSuchObject as exc:
print(exc.description)