Django中的許可(Permissions)和用戶組(Group)
接着上面的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:
user.hash_perm('school.add_studygroup') user.hash_perm('school.change_studygroup') user.hash_perm('school.delete_studygroup')
當然,我們也可以自己定義一些許可。方法很簡單,就是在Model類的meta屬性中添加permissions定義。比方說,創建了一個模型類叫做Discussion,我們可以創建幾個權限來對這個模型的權限許可進行控制,控制某些人可以發起討論、發起回復,關閉討論。
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, ...)
比如我們要判斷一個用戶是否有發討論的權限,我們可以用下面的代碼:
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的方法。
編程創建權限:
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。
比方說我們可以這樣判斷一個用戶是否是登陸用戶,進而作出不同的顯示:
{% 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屬性類型相同。我們可以通過:
group.permissions = [permission_list] group.permissions.add(permission, permission, ...) group.permissions.remove(permission, permission, ...) group.permissions.clear()
給該組賦予權限。
在下一篇博文中,我們將討論Django內置的權限控制系統中的核心部件,backend,作為討論Django內置權限控制的最后的一篇。