–更新于:2016-07-13

近期重写这部分,使其成为django management command (在dogwood版本下测试可用)

原因有二,其一是之前所用的功能函数不完备,随着对edx的了解深入,想用更安全的函数来完成批量注册功能,其二是希望做到更好的内聚性

这部分是从我的edx_siteapi抽出的一个功能模块,edx_siteapi项目试图把edx的一些功能变为RESTful api接口(类似canvas做的),供外部系统调用和整合,有兴趣的小伙伴可以关注这个项目


在搭建edX的时候,可能面临一个这样的需求:批量导入学生作为用户。
即便是采用cas注册这个需求可能依旧存在,校内系统可能存有用户课程关系,需要预先导入,所以用户实体需要预先存在系统中,而cas是一种首次登录才注册的机制

有时我们可能需要批量从既有数据库中导入用户,尤其是将Open edX用于SPOC中时

在此给出一个可行的解决方案。

大体思路

  • 从校方数据库中导出用户文件(csv格式)
  • 写脚本从csv文件中取得所需的字段(诸如学号,姓名)
  • 使用django management command将用户导入系统(利用django management command能调用django上下文的机制,这也是此次更新的主要地方)

##实施细节

我们假设从数据库导出的文件student.csv 如下

1
2
3
4
5
6
:::text
姓名,学号,email,专业,班级
张三,201011,zs@qq.com,热能动力工程,动力1007班
李四,201012,ls@qq.com,热能动力工程,动力1008班
王五,201013,ww@qq.com,热能动力工程,动力1009班
...

注意逗号前后的空格是有影响的!

###编写脚本 在任意django app目录下创建management/commands/create_user_from_csv.py,先上代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#!/usr/bin/env python
# encoding: utf-8
from optparse import make_option
from django.core.management.base import BaseCommand

from student.forms import AccountCreationForm
from student.models import create_comments_service_user
from student.views import _do_create_account, AccountValidationError
from track.management.tracked_command import TrackedCommand
# 解析csv
import unicodecsv  # utf-8 ,也可以用pandas:


def create_user(username, password, email, name):
    form = AccountCreationForm(data={
        'username': username,
        'email': email,
        'password': password,
        'name': name,
    },
                               tos_required=False)
    try:
        user, _, reg = _do_create_account(form)
        reg.activate()
        reg.save()
        #create_comments_service_user(user) #这会促发网络请求
        return user
    except AccountValidationError as e:
        print e.message


# wget https://raw.githubusercontent.com/edx/edx-platform/named-release/dogwood.rc/common/djangoapps/student/management/commands/create_user.py
class Command(TrackedCommand):
    help = """
    example:
        # Enroll a user test@example.com into the demo course
        # The username and name will default to "test"
        sudo -u www-data /edx/bin/python.edxapp /edx/app/edxapp/edx-platform/manage.py lms create_user_from_csv --help --settings devstack
        sudo -u www-data /edx/bin/python.edxapp /edx/app/edxapp/edx-platform/manage.py lms create_user_from_csv --csv /edx/app/edxapp/edx-platform/lms/djangoapps/siteapi/student.csv --settings devstack
    """
    help = u"批量导入用户"
    option_list = BaseCommand.option_list + (
        make_option('-c', '--csv', #采用绝对路径
                    metavar='CSV',
                    dest='csv',
                    default=None,
                    help=u'用户注册表'),
        )

    def handle(self, *args, **options):
        csv = options['csv']
        with open(csv) as f:
            f_csv = unicodecsv.DictReader(f, encoding='utf-8')
            for item in f_csv:
                print item[u"姓名"]
                username = item[u"学号"]
                email = item[u"email"]
                name = item[u"姓名"]
                password = username
                create_user(username, password, email, name)
        # 缺乏读写csv的技巧,next和边界,按header读取
        # http://python3-cookbook.readthedocs.io/zh_CN/latest/c06/p01_read_write_csv_data.html

测试显示,8000名学生的话,大约需要导入十几分钟(旧版本)

###安装依赖

1
2
:::text
sudo /edx/bin/pip.edxapp install unicodecsv #dogwood版不需要

###开始导入 sudo -u www-data /edx/bin/python.edxapp /edx/app/edxapp/edx-platform/manage.py lms create_user_from_csv --csv /tmp/student.csv --settings devstack

###开始使用 在/login中使用email和password登录即可。

对于不想使用这种登录方式的,可以自己来写用户认证,诸如使用username和password登录之类的

###后记 文中我们创建用户使用的是python代码。

如果是单独创建用户,也可以用

1
sudo -u www-data /edx/bin/python.edxapp /edx/app/edxapp/edx-platform/manage.py lms  create_user --username test123 --name test123  --password test123 --email test123@qq.com 

如果你愿意也可以采用http请求创建,详情可以跟踪sysadmin里的创建用户功能(封装成restful接口可用作异构系统接口)

删除用户之后创建同名用户,会造成:CommentClientRequestError: u’[“Username is already taken”]‘,猜测是评论系统内依然留存有用户造成的,而评论系统是个异构系统(mongodb)

线索:

  • import lms.lib.comment_client as cc
  • cc_user = cc.User.from_django_user(user)

解决方案

如果我们的猜测是对的,应该只要删除点mongodb中的user应该就好了

1
2
3
4
5
:::text
mongo
use cs_comments_service_development
db.users.find()
db.users.remove({}) #移除所有,也可以写到python脚本里,使用pymongo

一切正常,猜测正确!