diff --git a/django/contrib/auth/backends.py b/django/contrib/auth/backends.py
index 05f9835..6a5df18 100644
a
|
b
|
class ModelBackend(object):
|
21 | 21 | except User.DoesNotExist: |
22 | 22 | return None |
23 | 23 | |
24 | | def get_group_permissions(self, user_obj): |
| 24 | def get_group_permissions(self, user_obj, obj=None): |
25 | 25 | """ |
26 | 26 | Returns a set of permission strings that this user has through his/her |
27 | 27 | groups. |
28 | 28 | """ |
| 29 | if obj: return [] # We don't support rowlevel permissions with this backend. |
29 | 30 | if not hasattr(user_obj, '_group_perm_cache'): |
30 | 31 | cursor = connection.cursor() |
31 | 32 | # The SQL below works out to the following, after DB quoting: |
… |
… |
class ModelBackend(object):
|
55 | 56 | user_obj._group_perm_cache = set(["%s.%s" % (row[0], row[1]) for row in cursor.fetchall()]) |
56 | 57 | return user_obj._group_perm_cache |
57 | 58 | |
58 | | def get_all_permissions(self, user_obj): |
| 59 | def get_all_permissions(self, user_obj, obj=None): |
| 60 | if obj: return [] # We don't support rowlevel permissions with this backend. |
59 | 61 | if not hasattr(user_obj, '_perm_cache'): |
60 | 62 | user_obj._perm_cache = set([u"%s.%s" % (p.content_type.app_label, p.codename) for p in user_obj.user_permissions.select_related()]) |
61 | 63 | user_obj._perm_cache.update(self.get_group_permissions(user_obj)) |
62 | 64 | return user_obj._perm_cache |
63 | 65 | |
64 | | def has_perm(self, user_obj, perm): |
65 | | return perm in self.get_all_permissions(user_obj) |
| 66 | def has_perm(self, user_obj, perm, obj=None): |
| 67 | return perm in self.get_all_permissions(user_obj, obj) |
66 | 68 | |
67 | 69 | def has_module_perms(self, user_obj, app_label): |
68 | 70 | """ |
69 | 71 | Returns True if user_obj has any permissions in the given app_label. |
70 | 72 | """ |
71 | | for perm in self.get_all_permissions(user_obj): |
| 73 | for perm in self.get_all_permissions(user_obj, None): |
72 | 74 | if perm[:perm.index('.')] == app_label: |
73 | 75 | return True |
74 | 76 | return False |
diff --git a/django/contrib/auth/models.py b/django/contrib/auth/models.py
index e337bec..06d591b 100644
a
|
b
|
|
1 | 1 | import datetime |
2 | 2 | import urllib |
3 | 3 | |
| 4 | from warnings import warn as warn_ |
| 5 | |
4 | 6 | from django.contrib import auth |
5 | 7 | from django.core.exceptions import ImproperlyConfigured |
6 | 8 | from django.db import models |
… |
… |
from django.utils.translation import ugettext_lazy as _
|
12 | 14 | |
13 | 15 | UNUSABLE_PASSWORD = '!' # This will never be a valid hash |
14 | 16 | |
| 17 | def warn(method_name): |
| 18 | warn_("Backend.%s needs to support obj as last parameter.", |
| 19 | PendingDeprecationWarning, stacklevel=3) |
| 20 | |
15 | 21 | try: |
16 | 22 | set |
17 | 23 | except NameError: |
… |
… |
class User(models.Model):
|
194 | 200 | def has_usable_password(self): |
195 | 201 | return self.password != UNUSABLE_PASSWORD |
196 | 202 | |
197 | | def get_group_permissions(self): |
| 203 | def get_group_permissions(self, obj=None): |
198 | 204 | """ |
199 | 205 | Returns a list of permission strings that this user has through |
200 | 206 | his/her groups. This method queries all available auth backends. |
| 207 | If an object is passed in, only permissions matching this object |
| 208 | are returned. |
201 | 209 | """ |
202 | 210 | permissions = set() |
203 | 211 | for backend in auth.get_backends(): |
204 | 212 | if hasattr(backend, "get_group_permissions"): |
205 | | permissions.update(backend.get_group_permissions(self)) |
| 213 | try: |
| 214 | permissions.update(backend.get_group_permissions(self, obj)) |
| 215 | except TypeError: |
| 216 | # Backend doesn't support rowlevel perms, but still call it for now. |
| 217 | warn('get_group_permissions') |
| 218 | if not obj: |
| 219 | permissions.update(backend.get_group_permissions(self)) |
206 | 220 | return permissions |
207 | 221 | |
208 | | def get_all_permissions(self): |
| 222 | def get_all_permissions(self, obj=None): |
209 | 223 | permissions = set() |
210 | 224 | for backend in auth.get_backends(): |
211 | 225 | if hasattr(backend, "get_all_permissions"): |
212 | | permissions.update(backend.get_all_permissions(self)) |
| 226 | try: |
| 227 | permissions.update(backend.get_all_permissions(self, obj)) |
| 228 | except TypeError: |
| 229 | # Backend doesn't support rowlevel perms |
| 230 | warn('get_all_permissions') |
| 231 | if not obj: |
| 232 | permissions.update(backend.get_all_permissions(self)) |
213 | 233 | return permissions |
214 | 234 | |
215 | | def has_perm(self, perm): |
| 235 | def has_perm(self, perm, obj=None): |
216 | 236 | """ |
217 | 237 | Returns True if the user has the specified permission. This method |
218 | 238 | queries all available auth backends, but returns immediately if any |
219 | 239 | backend returns True. Thus, a user who has permission from a single |
220 | | auth backend is assumed to have permission in general. |
| 240 | auth backend is assumed to have permission in general. If an object |
| 241 | is provided, permissions for this specific object are checked. |
221 | 242 | """ |
222 | 243 | # Inactive users have no permissions. |
223 | 244 | if not self.is_active: |
… |
… |
class User(models.Model):
|
230 | 251 | # Otherwise we need to check the backends. |
231 | 252 | for backend in auth.get_backends(): |
232 | 253 | if hasattr(backend, "has_perm"): |
233 | | if backend.has_perm(self, perm): |
234 | | return True |
| 254 | try: |
| 255 | if backend.has_perm(self, perm, obj): |
| 256 | return True |
| 257 | except TypeError: |
| 258 | # Backend doesn't support rowlevel perms |
| 259 | warn('has_perm') |
| 260 | if not obj: |
| 261 | if backend.has_perm(self, perm): |
| 262 | return True |
235 | 263 | return False |
236 | 264 | |
237 | | def has_perms(self, perm_list): |
238 | | """Returns True if the user has each of the specified permissions.""" |
| 265 | def has_perms(self, perm_list, obj=None): |
| 266 | """Returns True if the user has each of the specified permissions. |
| 267 | If object is passed, it checks if the user has all required perms |
| 268 | for this object. |
| 269 | """ |
239 | 270 | for perm in perm_list: |
240 | | if not self.has_perm(perm): |
| 271 | if not self.has_perm(perm, obj): |
241 | 272 | return False |
242 | 273 | return True |
243 | 274 | |
diff --git a/docs/topics/auth.txt b/docs/topics/auth.txt
index 0fdf8b3..8409016 100644
a
|
b
|
Methods
|
196 | 196 | :meth:`~django.contrib.auth.models.User.set_unusable_password()` has |
197 | 197 | been called for this user. |
198 | 198 | |
199 | | .. method:: models.User.get_group_permissions() |
| 199 | .. method:: models.User.get_group_permissions(obj=None) |
200 | 200 | |
201 | 201 | Returns a list of permission strings that the user has, through his/her |
202 | | groups. |
| 202 | groups. If obj is passed in, only returns the group permissions for this |
| 203 | specific object. |
203 | 204 | |
204 | | .. method:: models.User.get_all_permissions() |
| 205 | .. method:: models.User.get_all_permissions(obj=None) |
205 | 206 | |
206 | 207 | Returns a list of permission strings that the user has, both through |
207 | | group and user permissions. |
| 208 | group and user permissions. If obj is passed in, only returns the |
| 209 | permissions for this specific object. |
208 | 210 | |
209 | | .. method:: models.User.has_perm(perm) |
| 211 | .. method:: models.User.has_perm(perm, obj) |
210 | 212 | |
211 | 213 | Returns ``True`` if the user has the specified permission, where perm is |
212 | 214 | in the format ``"<application name>.<lowercased model name>"``. If the |
213 | | user is inactive, this method will always return ``False``. |
| 215 | user is inactive, this method will always return ``False``. If obj is |
| 216 | passed in this method won't check the permissions for the model, but |
| 217 | the object. |
214 | 218 | |
215 | 219 | .. method:: models.User.has_perms(perm_list) |
216 | 220 | |
217 | 221 | Returns ``True`` if the user has each of the specified permissions, |
218 | 222 | where each perm is in the format ``"package.codename"``. If the user is |
219 | | inactive, this method will always return ``False``. |
| 223 | inactive, this method will always return ``False``. If obj is passed in |
| 224 | this method won't check the permissions for the model, but the object. |
220 | 225 | |
221 | 226 | .. method:: models.User.has_module_perms(package_name) |
222 | 227 | |