Reference: http://www.cnblogs.com/esperyong/archive/2012/12/20/2826690.html
接着上面的3篇討論文章,我們闡述了Django中如何使用Authentication系統進行,用戶的創建,登陸,登出,完成了用戶的認證。接下來,我們要看另外一個議題,那就是Authorization授權。在Django中這部分使用Permission來簡單完成的。在這篇文章中,我們要對Permission進行一下研究。
Django中的Permissions設置,主要通過Django自帶的Admin界面進行維護。主要通過設置某些用戶對應於某類模型的add\change\delete三種類型的權限,即是設置某些人對某些模型能夠增加、修改、刪除的權限設置。
Permission不僅僅能夠設置某類模型,還可以針對一個模型的某一個對象進行設置。
許可(Permissions)
其實,當我們在django中安裝好了auth應用之后,Django就會被每一個你安裝的app中的Model創建三個權限:add,change,delete;相應的數據,就是在你執行python manage.py syncdb之后插入到數據庫中的。每一次你執行syncdb,Django都會為每個用戶給新出現的Model增加這三個權限。
例如,你創建了一個應用叫做school,里面有一個模型叫做StudyGroup,那么你可以用任何一個user對象執行下面的程序,其結果都返回True:
1
2
3
|
user.hash_perm(
'school.add_studygroup'
)
user.hash_perm(
'school.change_studygroup'
)
user.hash_perm(
'school.delete_studygroup'
)
|
當然,我們也可以自己定義一些許可。方法很簡單,就是在Model類的meta屬性中添加permissions定義。比方說,創建了一個模型類叫做Discussion,我們可以創建幾個權限來對這個模型的權限許可進行控制,控制某些人可以發起討論、發起回復,關閉討論。
1
2
3
4
5
6
7
8
|
class
Discussion(models.Model):
...
class
Meta:
permissions
=
(
(
"open_discussion"
,
"Can create a discussion"
),
(
"reply_discussion"
,
"Can reply discussion"
),
(
"close_discussion"
,
"Can remove a discussion by setting its status as closed"
),
)
|
接下來要做的就是最后一步,執行manage.py syncdb,這樣數據庫中就有了這三個許可了。
我們可以將上面的權限賦予用戶,方法有兩種:
- 通過某一個user的user_permissions屬性(文章1中有提及):
user.user_permissions.add(permission, permission, ...)
- 通過user的一個組,然后通過Group的permissions屬性:
group.permissions.add(permission, permission, ...)
比如我們要判斷一個用戶是否有發討論的權限,我們可以用下面的代碼:
1
|
user.has_perm(
'school.open_discussion'
)
|
Permission類和User類沒什么特殊的,都是普通的DjangoModel。在第一篇文章中我們詳細探討了User模型的屬性和方法。在這里我們探討一下Permission模型和如何用編程的方式而不是通過預定義然后syncdb的方式創建permission。因為也許在某些時候,需要動態創建並分配權限。
Permission 屬性:
所屬模塊:django.contrib.auth.models
屬性:
- name:必填。小於50個字符。例如:'Can publish'。
- content_type:必填。一個指向django_content_type數據庫表,對於每一個Django模型,在這個表里面都有一個記錄對應。
- codename:必填。小於100個字符。例如:'can_publish'。
方法:沒有特殊方法。具有所有普通DjangoModel的方法。
編程創建權限:
1
2
3
4
5
6
7
|
from
django.contrib.auth.models
import
Group, Permission
from
django.contrib.contenttypes.models
import
ContentType
content_type
=
ContentType.objects.get(app_label
=
'school'
, model
=
'Discussion'
)
permission
=
Permission.objects.create(codename
=
'can_publish'
,
name
=
'Can Publish Discussions'
,
content_type
=
content_type)
|
在界面中使用許可
接下來,我們需要探討一下如何在Template(模板)中使用許可。因為有的時候需要在界面上,通過一些許可來控制界面的顯示。
在Django中在界面上進行權限設置非常方便,因為Django為你做了很多工作。
在模版代碼中,有兩個屬性,是Django給你提供好的,一個是user,一個是perms。
比方說我們可以這樣判斷一個用戶是否是登陸用戶,進而作出不同的顯示:
1
2
3
4
5
|
{% if user.is_authenticated %}
<
p
>Welcome, {{ user.username }}. Thanks for logging in.</
p
>
{% else %}
<
p
>Welcome, new user. Please log in.</
p
>
{% endif %}
|
user變量是一個User或者AnoymousUser對象。
perms變量是一個django.contrib.auth.context_processors.PermWrapper對象,對當前用戶的User.has_module_perms和User.has_perm進行了封裝。這個包裝器讓你使用perm起來非常的方便。比如,我們需要判斷當前用戶是否擁有school應用下的所有權限,則使用
{{perms.school}}
我們如果判斷當前用戶是否擁有school應用下發表討論的權限,則使用{{perms.school.publish_discussion}}
這樣結合template的if標簽,我們可以通過判斷當前用戶所具有的權限,顯示不同的界面了:
{% if perms.school %}
<
p
>You have permission to do something in the school app.</
p
>
{% if perms.school.publish_discussion %}
<
p
>You can discussion!</
p
>
{% endif %}
{% if perms.school.reply_discussion %}
<
p
>You can reply discussion!</
p
>
{% endif %}
{% else %}
<
p
>You don't have permission to do anything in the school app.</
p
>
{% endif %}
|
當然,我們不禁要問,在模版中為何會有這兩個變量呢?Django是如何做到的呢?答案是:settings 中的TEMPLATE_CONTEXT_PROCESSORS中定義的django.contrib.auth.context_processors.auth處理器。在Django進入解析Template之前,首先要經過這一個個的context_processor。其中django.contrib.auth.context_processors.auth就是將user和perms這倆對象放到TemplateContext中去的。
另外,我們還需要使用RequestContext作為TemplateContext。例如:
from
django.template
import
RequestContext
from
django.shortcuts
import
render_to_response
def
someview(request):
...view logic
ctx
=
{somekey:somevalue}
return
render_to_response(
'instances/accounts/tparts/update_share_limit_form.html'
,
ctx,
context_instance
=
RequestContext(request))
|
確保上述兩個要點,我們在template中使用權限控制就非常的簡單了。
接下來我們簡單說一下最后一個核心模型:用戶組。
用戶組(Group)
用戶組模型很簡單,和User模型是多對多的關系。用戶組顧名思義,就是對用戶進行了分組。其作用在權限控制中就是可以批量的對用戶的許可進行分配,而不用一個一個的按用戶分配,節省維護的工作量。
將一個用戶加入到一個Group中,該用戶就擁有了該Group所分配的所有許可。例如,如果一個組teachers有許可can_create_lesson。那么所有屬於teachers組的用戶都會有這個權限。
Group:
屬性:
- name:必須。少於80個字符。
- permissions:多對多引用。和user的user_permissions屬性類型相同。我們可以通過:
1234
group.permissions
=
[permission_list]
group.permissions.add(permission, permission, ...)
group.permissions.remove(permission, permission, ...)
group.permissions.clear()
給該組賦予權限。