Repository: ckan/ckan

Issue:
Add a user_list option that returns just names instead of dicts
user_list currently returns a dict for each user and the enhancement is to add an option to allow returning the user names.

DGU has 30k users and it takes 3 minutes, which is no good for a web request. Whereas returning just the names takes 10 seconds, skipping the dictization and the additional parts of the query that adds up revisions by the user.

package_list and group_list both return either names or dicts, depending on the `all_fields` parameter, so the proposal is to do the same, the only difference being that the default is True, for backward compatibility. (Other list actions just return dicts.)


Discussion:

Resolving patch:
diff --git a/ckan/logic/action/get.py b/ckan/logic/action/get.py
--- a/ckan/logic/action/get.py
+++ b/ckan/logic/action/get.py
@@ -818,6 +818,9 @@ def user_list(context, data_dict):
     :param order_by: which field to sort the list by (optional, default:
       ``'name'``). Can be any user field or ``edits`` (i.e. number_of_edits).
     :type order_by: string
+    :param all_fields: return full user dictionaries instead of just names.
+      (optional, default: ``True``)
+    :type all_fields: boolean
 
     :rtype: list of user dictionaries. User properties include:
       ``number_of_edits`` which counts the revisions by the user and
@@ -831,26 +834,30 @@ def user_list(context, data_dict):
 
     q = data_dict.get('q', '')
     order_by = data_dict.get('order_by', 'name')
+    all_fields = asbool(data_dict.get('all_fields', True))
 
-    query = model.Session.query(
-        model.User,
-        model.User.name.label('name'),
-        model.User.fullname.label('fullname'),
-        model.User.about.label('about'),
-        model.User.about.label('email'),
-        model.User.created.label('created'),
-        _select([_func.count(model.Revision.id)],
-                _or_(
-                    model.Revision.author == model.User.name,
-                    model.Revision.author == model.User.openid
-                )).label('number_of_edits'),
-        _select([_func.count(model.Package.id)],
-                _and_(
-                    model.Package.creator_user_id == model.User.id,
-                    model.Package.state == 'active',
-                    model.Package.private == False,
-                )).label('number_created_packages')
-    )
+    if all_fields:
+        query = model.Session.query(
+            model.User,
+            model.User.name.label('name'),
+            model.User.fullname.label('fullname'),
+            model.User.about.label('about'),
+            model.User.about.label('email'),
+            model.User.created.label('created'),
+            _select([_func.count(model.Revision.id)],
+                    _or_(
+                        model.Revision.author == model.User.name,
+                        model.Revision.author == model.User.openid
+                    )).label('number_of_edits'),
+            _select([_func.count(model.Package.id)],
+                    _and_(
+                        model.Package.creator_user_id == model.User.id,
+                        model.Package.state == 'active',
+                        model.Package.private == False,
+                    )).label('number_created_packages')
+        )
+    else:
+        query = model.Session.query(model.User.name)
 
     if q:
         query = model.User.search(q, query, user_name=context.get('user'))
@@ -861,7 +868,6 @@ def user_list(context, data_dict):
                     _or_(
                         model.Revision.author == model.User.name,
                         model.Revision.author == model.User.openid))))
-
     else:
         query = query.order_by(
             _case([(
@@ -879,9 +885,13 @@ def user_list(context, data_dict):
 
     users_list = []
 
-    for user in query.all():
-        result_dict = model_dictize.user_dictize(user[0], context)
-        users_list.append(result_dict)
+    if all_fields:
+        for user in query.all():
+            result_dict = model_dictize.user_dictize(user[0], context)
+            users_list.append(result_dict)
+    else:
+        for user in query.all():
+            users_list.append(user[0])
 
     return users_list
 


Test patch:
diff --git a/ckan/tests/logic/action/test_get.py b/ckan/tests/logic/action/test_get.py
--- a/ckan/tests/logic/action/test_get.py
+++ b/ckan/tests/logic/action/test_get.py
@@ -570,6 +570,16 @@ def test_user_list_excludes_deleted_users(self):
         assert len(got_users) == 1
         assert got_users[0]['name'] == user['name']
 
+    def test_user_list_not_all_fields(self):
+
+        user = factories.User()
+
+        got_users = helpers.call_action('user_list', all_fields=False)
+
+        assert len(got_users) == 1
+        got_user = got_users[0]
+        assert got_user == user['name']
+
 
 class TestUserShow(helpers.FunctionalTestBase):