該項目中提供了注冊和登錄兩部分功能,功能描述如下:
注冊:
允許任何用戶進行學生身份的注冊。
教師用戶預先已經保存在數據庫中,不允許以游客身份注冊新的教師用戶。
注冊時需要填寫的信息包括:
- 用戶名
- 密碼(確認密碼)
- 郵箱
登錄:
允許教師和學生兩類用戶組中的用戶進行登錄。
登錄時需要填寫的信息包括:
- 用戶名
- 密碼
登錄成功后,根據不同用戶所屬的用戶組,進入相應的頁面。
第一部分 注冊功能
首先貼上注冊部分的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
框架也會在后面章節中進行說明。