该项目中提供了注册和登录两部分功能,功能描述如下:
注册:
允许任何用户进行学生身份的注册。
教师用户预先已经保存在数据库中,不允许以游客身份注册新的教师用户。
注册时需要填写的信息包括:
- 用户名
- 密码(确认密码)
- 邮箱
登录:
允许教师和学生两类用户组中的用户进行登录。
登录时需要填写的信息包括:
- 用户名
- 密码
登录成功后,根据不同用户所属的用户组,进入相应的页面。
第一部分 注册功能
首先贴上注册部分的views代码片:
@csrf_protect
def student_register(request): errors= [] account=None password=None password2=None email=None CompareFlag=False if request.method == 'POST': if not request.POST.get('account'): errors.append('Please Enter account') else: account = request.POST.get('account') if not request.POST.get('password'): errors.append('Please Enter password') else: password = request.POST.get('password')if not request.POST.get('password2'): errors.append('Please Enter password2') else: password2 = request.POST.get('password2') if not request.POST.get('email'): errors.append('Please Enter email') else: email = request.POST.get('email')if password is not None and password2 is not None: if password == password2: CompareFlag = True else : errors.append('password2 is diff password ') if account is not None and password is not None and password2 is not None and email is not None and CompareFlag : if User.objects.filter(username=account):errors.append('this account already exists, Please change another username')else:user=User.objects.create_user(account,email,password) user.is_active=Truepermission=Permission.objects.get(name='student')user.user_permissions.add(permission)user.save()return HttpResponseRedirect('../../')return render_to_response('account/register.html', {'errors': errors}, context_instance=RequestContext(request))
水平不足,代码十分简陋,此处只对当时感到困惑的一些问题进行说明了。
Q1:如何返回带有form
(表单)的页面
根据Django框架的设定,访问某url
时,首先调用views
中对应函数,根据函数返回值传回相应context
及html
。大多数使用form
元素时,是为了使用post/get
的方法向网站传回表单中的数据。但是在初次访问该页面时,没有表单提交的请求,所以在views
中的处理函数中如果直接写处理表单数据的代码,系统会报错,因为函数无法从get
请求中获取到所需的数据进行相应的操作。
会发生这个问题的原因是对网站逻辑了解模糊,敲代码时关注了提交表单后的数据处理,却忽略了首次访问时如何进入界面的问题。
解决办法是:
views
函数中对数据进行处理前先进行逻辑判断,“请求头里面是否有该数据”,没有的话返回原页面,并且提示相应信息。
代码实现:
if request.method == 'POST': if not request.POST.get('account'): errors.append('Please Enter account') else: account = request.POST.get('account') if not request.POST.get('password'): errors.append('Please Enter password') else: password = request.POST.get('password')if not request.POST.get('password2'): errors.append('Please Enter password2') else: password2 = request.POST.get('password2') if not request.POST.get('email'): errors.append('Please Enter email') else: email = request.POST.get('email')if password is not None and password2 is not None: if password == password2: CompareFlag = True else : errors.append('password2 is diff password ')
return render_to_response('account/register.html', {'errors': errors}, context_instance=RequestContext(request))
第二部分 登陆功能
登录部分代码片:
@csrf_protect
def alogin(request):errors=[]account=Nonepassword=Noneif request.user.is_authenticated():if request.user.has_perm('auth.is_teacher'):return HttpResponseRedirect('/update')else:return HttpResponseRedirect('/main')else:if request.method == 'POST':if not request.POST.get('account'):errors.append('Please Enter account')else:account = request.POST.get('account')if not request.POST.get('password'):errors.append('Please Enter password')else:password = request.POST.get('password')if account is not None and password is not None:user = authenticate(username=account,password=password)if user is not None:if user.is_active :login(request,user)if user.has_perm('auth.is_teacher') :return HttpResponseRedirect('/update')else:return HttpResponseRedirect('/main')else:errors.append('disabled account')else:errors.append('invalid user')return render_to_response('account/login.html',{'errors':errors}, context_instance=RequestContext(request))
Q1:用户权限管理
如上所述,用户分为教师和学生。用来区分学生和教师的方法是分别赋予两类user的user_permissions不同的值。
user_permissions也是Django框架中内置的一类模型,用于管理一个user所具有的权限。auth_user_user_permissions(即user_permission在Django框架中的名字)的table形式为:
id | user_id | permisson_id |
---|---|---|
1 | 10 | 30 |
2 | 16 | 28 |
x | xx | xx |
id表示user_permission的id,user_id和permission_id即代表某个user以及该user所对应的permission有哪些,此处的permission_id为数组形式。
permission_id对应的permission又存储在auth_permission这个table中,其内容大致为:
id | name | content_type_id | codename |
---|---|---|---|
1 | Can add log entry | 1 | add_logentry |
2 | Can change log entry | 1 | change_logentry |
3 | Can delete log entry | 1 | delete_logentry |
4 | Can add permission | 2 | add_permission |
5 | Can change permission | 2 | change_permission |
6 | Can delete permission | 2 | delete_permission |
7 | Can add group | 3 | add_group |
8 | Can change group | 3 | change_group |
9 | Can delete group | 3 | delete_group |
10 | Can add user | 4 | add_user |
11 | Can change user | 4 | change_user |
x | xxxx | xxxx | xxx |
30 | teacher | 4 | is_teacher |
31 | student | 4 | is_student |
可以观察到除了30、31行比较特殊外,其余内容比较相似。是因为其他部分都是Django内部自动为每个model生成的,其中包括了内置的如user、group等。
而teacher、student两个则是此项目中手工添加的权限,可以看到,此处teacher和student两个权限的id分别为30和31,对应着前一个表格中的permission_id一列。
以上为实现权限管理功能所做的准备,以及相关数据的说明。接下来简单说一下代码部分是如何实现这个功能的。
在登录函数中,权限判断的代码如下:
if request.user.is_authenticated():if request.user.has_perm('auth.is_teacher'):return HttpResponseRedirect('/update')else:return HttpResponseRedirect('/main')
user.has_perm('xx')
是user的方法之一,用来检查user.user_permission中是否有权限“xxx”存在,此处“xxx”是permission的codename(详见上面表格)。
Q2:用户认证
用户认证的部分代码如下:
if account is not None and password is not None:user = authenticate(username=account,password=password)if user is not None:if user.is_active :login(request,user)if user.has_perm('auth.is_teacher') :return HttpResponseRedirect('/update')else:return HttpResponseRedirect('/main')else:errors.append('disabled account')else:errors.append('invalid user')
其中值得我们关注的部分有: authenticate(username,password)
user.is_active
login(request,user)
1.authenticate(username,password)
:该函数接受两个参数username
和 password
,如果该用户名和密码匹配,则返回该user
对象;如果不匹配,则返回 None
值。
2.user.is_active
:是否允许用户登录, 设置为False
,可以不用删除用户来禁止用户登录.
3.login(request,user)
:该函数接受一个HttpRequest
对象和一个 User
对象作为参数并使用Django
的会话( session
)框架把用户的ID保存在该会话中.
Ps:关于Django的Session框架会在后面的部分单独介绍。
Pps:csrf_protect
机制及csrf
框架也会在后面章节中进行说明。