Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed #11410 -- Moved the "Groups" field to the "Permissions" module …

…in the `auth.User` admin form and modified the help texts for the `user_permissions` and `groups` model fields to reflect that change. Also did a little PEP8 cleanup and improved some docstrings while I was in the area. Thanks to benspaulding and Aymeric Augustin for the suggestions.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@17325 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit cb99b598c1b868016f82a1d8c3b957f0277fba2c 1 parent 8af9084
Julien Phalip authored January 02, 2012
27  django/contrib/auth/admin.py
... ...
@@ -1,7 +1,8 @@
1 1
 from django.db import transaction
2 2
 from django.conf import settings
3 3
 from django.contrib import admin
4  
-from django.contrib.auth.forms import UserCreationForm, UserChangeForm, AdminPasswordChangeForm
  4
+from django.contrib.auth.forms import (UserCreationForm, UserChangeForm,
  5
+    AdminPasswordChangeForm)
5 6
 from django.contrib.auth.models import User, Group
6 7
 from django.contrib import messages
7 8
 from django.core.exceptions import PermissionDenied
@@ -27,7 +28,8 @@ def formfield_for_manytomany(self, db_field, request=None, **kwargs):
27 28
             # Avoid a major performance hit resolving permission names which
28 29
             # triggers a content_type load:
29 30
             kwargs['queryset'] = qs.select_related('content_type')
30  
-        return super(GroupAdmin, self).formfield_for_manytomany(db_field, request=request, **kwargs)
  31
+        return super(GroupAdmin, self).formfield_for_manytomany(
  32
+            db_field, request=request, **kwargs)
31 33
 
32 34
 
33 35
 class UserAdmin(admin.ModelAdmin):
@@ -36,9 +38,9 @@ class UserAdmin(admin.ModelAdmin):
36 38
     fieldsets = (
37 39
         (None, {'fields': ('username', 'password')}),
38 40
         (_('Personal info'), {'fields': ('first_name', 'last_name', 'email')}),
39  
-        (_('Permissions'), {'fields': ('is_active', 'is_staff', 'is_superuser', 'user_permissions')}),
  41
+        (_('Permissions'), {'fields': ('is_active', 'is_staff', 'is_superuser',
  42
+                                       'groups', 'user_permissions')}),
40 43
         (_('Important dates'), {'fields': ('last_login', 'date_joined')}),
41  
-        (_('Groups'), {'fields': ('groups',)}),
42 44
     )
43 45
     add_fieldsets = (
44 46
         (None, {
@@ -76,7 +78,8 @@ def get_form(self, request, obj=None, **kwargs):
76 78
     def get_urls(self):
77 79
         from django.conf.urls import patterns
78 80
         return patterns('',
79  
-            (r'^(\d+)/password/$', self.admin_site.admin_view(self.user_change_password))
  81
+            (r'^(\d+)/password/$',
  82
+             self.admin_site.admin_view(self.user_change_password))
80 83
         ) + super(UserAdmin, self).get_urls()
81 84
 
82 85
     @sensitive_post_parameters()
@@ -93,7 +96,11 @@ def add_view(self, request, form_url='', extra_context=None):
93 96
             if self.has_add_permission(request) and settings.DEBUG:
94 97
                 # Raise Http404 in debug mode so that the user gets a helpful
95 98
                 # error message.
96  
-                raise Http404('Your user does not have the "Change user" permission. In order to add users, Django requires that your user account have both the "Add user" and "Change user" permissions set.')
  99
+                raise Http404(
  100
+                    'Your user does not have the "Change user" permission. In '
  101
+                    'order to add users, Django requires that your user '
  102
+                    'account have both the "Add user" and "Change user" '
  103
+                    'permissions set.')
97 104
             raise PermissionDenied
98 105
         if extra_context is None:
99 106
             extra_context = {}
@@ -102,7 +109,8 @@ def add_view(self, request, form_url='', extra_context=None):
102 109
             'username_help_text': self.model._meta.get_field('username').help_text,
103 110
         }
104 111
         extra_context.update(defaults)
105  
-        return super(UserAdmin, self).add_view(request, form_url, extra_context)
  112
+        return super(UserAdmin, self).add_view(request, form_url,
  113
+                                               extra_context)
106 114
 
107 115
     @sensitive_post_parameters()
108 116
     def user_change_password(self, request, id):
@@ -112,7 +120,7 @@ def user_change_password(self, request, id):
112 120
         if request.method == 'POST':
113 121
             form = self.change_password_form(user, request.POST)
114 122
             if form.is_valid():
115  
-                new_user = form.save()
  123
+                form.save()
116 124
                 msg = ugettext('Password changed successfully.')
117 125
                 messages.success(request, msg)
118 126
                 return HttpResponseRedirect('..')
@@ -155,7 +163,8 @@ def response_add(self, request, obj, post_url_continue='../%s/'):
155 163
         # * We are adding a user in a popup
156 164
         if '_addanother' not in request.POST and '_popup' not in request.POST:
157 165
             request.POST['_continue'] = 1
158  
-        return super(UserAdmin, self).response_add(request, obj, post_url_continue)
  166
+        return super(UserAdmin, self).response_add(request, obj,
  167
+                                                   post_url_continue)
159 168
 
160 169
 admin.site.register(Group, GroupAdmin)
161 170
 admin.site.register(User, UserAdmin)
144  django/contrib/auth/models.py
@@ -16,6 +16,7 @@
16 16
 from django.contrib.auth.signals import user_logged_in
17 17
 from django.contrib.contenttypes.models import ContentType
18 18
 
  19
+
19 20
 def update_last_login(sender, user, **kwargs):
20 21
     """
21 22
     A signal receiver which updates the last_login date for
@@ -25,28 +26,42 @@ def update_last_login(sender, user, **kwargs):
25 26
     user.save()
26 27
 user_logged_in.connect(update_last_login)
27 28
 
  29
+
28 30
 class SiteProfileNotAvailable(Exception):
29 31
     pass
30 32
 
  33
+
31 34
 class PermissionManager(models.Manager):
32 35
     def get_by_natural_key(self, codename, app_label, model):
33 36
         return self.get(
34 37
             codename=codename,
35  
-            content_type=ContentType.objects.get_by_natural_key(app_label, model),
  38
+            content_type=ContentType.objects.get_by_natural_key(app_label,
  39
+                                                                model),
36 40
         )
37 41
 
  42
+
38 43
 class Permission(models.Model):
39  
-    """The permissions system provides a way to assign permissions to specific users and groups of users.
  44
+    """
  45
+    The permissions system provides a way to assign permissions to specific
  46
+    users and groups of users.
40 47
 
41  
-    The permission system is used by the Django admin site, but may also be useful in your own code. The Django admin site uses permissions as follows:
  48
+    The permission system is used by the Django admin site, but may also be
  49
+    useful in your own code. The Django admin site uses permissions as follows:
42 50
 
43  
-        - The "add" permission limits the user's ability to view the "add" form and add an object.
44  
-        - The "change" permission limits a user's ability to view the change list, view the "change" form and change an object.
  51
+        - The "add" permission limits the user's ability to view the "add" form
  52
+          and add an object.
  53
+        - The "change" permission limits a user's ability to view the change
  54
+          list, view the "change" form and change an object.
45 55
         - The "delete" permission limits the ability to delete an object.
46 56
 
47  
-    Permissions are set globally per type of object, not per specific object instance. It is possible to say "Mary may change news stories," but it's not currently possible to say "Mary may change news stories, but only the ones she created herself" or "Mary may only change news stories that have a certain status or publication date."
  57
+    Permissions are set globally per type of object, not per specific object
  58
+    instance. It is possible to say "Mary may change news stories," but it's
  59
+    not currently possible to say "Mary may change news stories, but only the
  60
+    ones she created herself" or "Mary may only change news stories that have a
  61
+    certain status or publication date."
48 62
 
49  
-    Three basic permissions -- add, change and delete -- are automatically created for each Django model.
  63
+    Three basic permissions -- add, change and delete -- are automatically
  64
+    created for each Django model.
50 65
     """
51 66
     name = models.CharField(_('name'), max_length=50)
52 67
     content_type = models.ForeignKey(ContentType)
@@ -57,7 +72,8 @@ class Meta:
57 72
         verbose_name = _('permission')
58 73
         verbose_name_plural = _('permissions')
59 74
         unique_together = (('content_type', 'codename'),)
60  
-        ordering = ('content_type__app_label', 'content_type__model', 'codename')
  75
+        ordering = ('content_type__app_label', 'content_type__model',
  76
+                    'codename')
61 77
 
62 78
     def __unicode__(self):
63 79
         return u"%s | %s | %s" % (
@@ -69,15 +85,27 @@ def natural_key(self):
69 85
         return (self.codename,) + self.content_type.natural_key()
70 86
     natural_key.dependencies = ['contenttypes.contenttype']
71 87
 
72  
-class Group(models.Model):
73  
-    """Groups are a generic way of categorizing users to apply permissions, or some other label, to those users. A user can belong to any number of groups.
74 88
 
75  
-    A user in a group automatically has all the permissions granted to that group. For example, if the group Site editors has the permission can_edit_home_page, any user in that group will have that permission.
76  
-
77  
-    Beyond permissions, groups are a convenient way to categorize users to apply some label, or extended functionality, to them. For example, you could create a group 'Special users', and you could write code that would do special things to those users -- such as giving them access to a members-only portion of your site, or sending them members-only email messages.
  89
+class Group(models.Model):
  90
+    """
  91
+    Groups are a generic way of categorizing users to apply permissions, or
  92
+    some other label, to those users. A user can belong to any number of
  93
+    groups.
  94
+
  95
+    A user in a group automatically has all the permissions granted to that
  96
+    group. For example, if the group Site editors has the permission
  97
+    can_edit_home_page, any user in that group will have that permission.
  98
+
  99
+    Beyond permissions, groups are a convenient way to categorize users to
  100
+    apply some label, or extended functionality, to them. For example, you
  101
+    could create a group 'Special users', and you could write code that would
  102
+    do special things to those users -- such as giving them access to a
  103
+    members-only portion of your site, or sending them members-only email
  104
+    messages.
78 105
     """
79 106
     name = models.CharField(_('name'), max_length=80, unique=True)
80  
-    permissions = models.ManyToManyField(Permission, verbose_name=_('permissions'), blank=True)
  107
+    permissions = models.ManyToManyField(Permission,
  108
+        verbose_name=_('permissions'), blank=True)
81 109
 
82 110
     class Meta:
83 111
         verbose_name = _('group')
@@ -86,6 +114,7 @@ class Meta:
86 114
     def __unicode__(self):
87 115
         return self.name
88 116
 
  117
+
89 118
 class UserManager(models.Manager):
90 119
     def create_user(self, username, email=None, password=None):
91 120
         """
@@ -119,13 +148,16 @@ def create_superuser(self, username, email, password):
119 148
         u.save(using=self._db)
120 149
         return u
121 150
 
122  
-    def make_random_password(self, length=10, allowed_chars='abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789'):
  151
+    def make_random_password(self, length=10,
  152
+                             allowed_chars='abcdefghjkmnpqrstuvwxyz'
  153
+                                           'ABCDEFGHJKLMNPQRSTUVWXYZ'
  154
+                                           '23456789'):
123 155
         """
124  
-        Generates a random password with the given length
125  
-        and given allowed_chars
  156
+        Generates a random password with the given length and given
  157
+        allowed_chars. Note that the default value of allowed_chars does not
  158
+        have "I" or "O" or letters and digits that look similar -- just to
  159
+        avoid confusion.
126 160
         """
127  
-        # Note that default value of allowed_chars does not have "I" or letters
128  
-        # that look like it -- just to avoid confusion.
129 161
         return get_random_string(length, allowed_chars)
130 162
 
131 163
 
@@ -169,23 +201,36 @@ def _user_has_module_perms(user, app_label):
169 201
 
170 202
 class User(models.Model):
171 203
     """
172  
-    Users within the Django authentication system are represented by this model.
  204
+    Users within the Django authentication system are represented by this
  205
+    model.
173 206
 
174 207
     Username and password are required. Other fields are optional.
175 208
     """
176  
-    username = models.CharField(_('username'), max_length=30, unique=True, help_text=_("Required. 30 characters or fewer. Letters, numbers and @/./+/-/_ characters"))
  209
+    username = models.CharField(_('username'), max_length=30, unique=True,
  210
+        help_text=_('Required. 30 characters or fewer. Letters, numbers and '
  211
+                    '@/./+/-/_ characters'))
177 212
     first_name = models.CharField(_('first name'), max_length=30, blank=True)
178 213
     last_name = models.CharField(_('last name'), max_length=30, blank=True)
179 214
     email = models.EmailField(_('e-mail address'), blank=True)
180 215
     password = models.CharField(_('password'), max_length=128)
181  
-    is_staff = models.BooleanField(_('staff status'), default=False, help_text=_("Designates whether the user can log into this admin site."))
182  
-    is_active = models.BooleanField(_('active'), default=True, help_text=_("Designates whether this user should be treated as active. Unselect this instead of deleting accounts."))
183  
-    is_superuser = models.BooleanField(_('superuser status'), default=False, help_text=_("Designates that this user has all permissions without explicitly assigning them."))
  216
+    is_staff = models.BooleanField(_('staff status'), default=False,
  217
+        help_text=_('Designates whether the user can log into this admin '
  218
+                    'site.'))
  219
+    is_active = models.BooleanField(_('active'), default=True,
  220
+        help_text=_('Designates whether this user should be treated as '
  221
+                    'active. Unselect this instead of deleting accounts.'))
  222
+    is_superuser = models.BooleanField(_('superuser status'), default=False,
  223
+        help_text=_('Designates that this user has all permissions without '
  224
+                    'explicitly assigning them.'))
184 225
     last_login = models.DateTimeField(_('last login'), default=timezone.now)
185 226
     date_joined = models.DateTimeField(_('date joined'), default=timezone.now)
186  
-    groups = models.ManyToManyField(Group, verbose_name=_('groups'), blank=True,
187  
-        help_text=_("In addition to the permissions manually assigned, this user will also get all permissions granted to each group he/she is in."))
188  
-    user_permissions = models.ManyToManyField(Permission, verbose_name=_('user permissions'), blank=True)
  227
+    groups = models.ManyToManyField(Group, verbose_name=_('groups'),
  228
+        blank=True, help_text=_('The groups this user belongs to. A user will '
  229
+                                'get all permissions granted to each of '
  230
+                                'his/her group.'))
  231
+    user_permissions = models.ManyToManyField(Permission,
  232
+        verbose_name=_('user permissions'), blank=True,
  233
+        help_text='Specific permissions for this user.')
189 234
     objects = UserManager()
190 235
 
191 236
     class Meta:
@@ -241,16 +286,16 @@ def has_usable_password(self):
241 286
 
242 287
     def get_group_permissions(self, obj=None):
243 288
         """
244  
-        Returns a list of permission strings that this user has through
245  
-        his/her groups. This method queries all available auth backends.
246  
-        If an object is passed in, only permissions matching this object
247  
-        are returned.
  289
+        Returns a list of permission strings that this user has through his/her
  290
+        groups. This method queries all available auth backends. If an object
  291
+        is passed in, only permissions matching this object are returned.
248 292
         """
249 293
         permissions = set()
250 294
         for backend in auth.get_backends():
251 295
             if hasattr(backend, "get_group_permissions"):
252 296
                 if obj is not None:
253  
-                    permissions.update(backend.get_group_permissions(self, obj))
  297
+                    permissions.update(backend.get_group_permissions(self,
  298
+                                                                     obj))
254 299
                 else:
255 300
                     permissions.update(backend.get_group_permissions(self))
256 301
         return permissions
@@ -263,8 +308,8 @@ def has_perm(self, perm, obj=None):
263 308
         Returns True if the user has the specified permission. This method
264 309
         queries all available auth backends, but returns immediately if any
265 310
         backend returns True. Thus, a user who has permission from a single
266  
-        auth backend is assumed to have permission in general. If an object
267  
-        is provided, permissions for this specific object are checked.
  311
+        auth backend is assumed to have permission in general. If an object is
  312
+        provided, permissions for this specific object are checked.
268 313
         """
269 314
 
270 315
         # Active superusers have all permissions.
@@ -276,9 +321,9 @@ def has_perm(self, perm, obj=None):
276 321
 
277 322
     def has_perms(self, perm_list, obj=None):
278 323
         """
279  
-        Returns True if the user has each of the specified permissions.
280  
-        If object is passed, it checks if the user has all required perms
281  
-        for this object.
  324
+        Returns True if the user has each of the specified permissions. If
  325
+        object is passed, it checks if the user has all required perms for this
  326
+        object.
282 327
         """
283 328
         for perm in perm_list:
284 329
             if not self.has_perm(perm, obj):
@@ -287,8 +332,8 @@ def has_perms(self, perm_list, obj=None):
287 332
 
288 333
     def has_module_perms(self, app_label):
289 334
         """
290  
-        Returns True if the user has any permissions in the given app
291  
-        label. Uses pretty much the same logic as has_perm, above.
  335
+        Returns True if the user has any permissions in the given app label.
  336
+        Uses pretty much the same logic as has_perm, above.
292 337
         """
293 338
         # Active superusers have all permissions.
294 339
         if self.is_active and self.is_superuser:
@@ -310,22 +355,23 @@ def get_profile(self):
310 355
         if not hasattr(self, '_profile_cache'):
311 356
             from django.conf import settings
312 357
             if not getattr(settings, 'AUTH_PROFILE_MODULE', False):
313  
-                raise SiteProfileNotAvailable('You need to set AUTH_PROFILE_MO'
314  
-                                              'DULE in your project settings')
  358
+                raise SiteProfileNotAvailable(
  359
+                    'You need to set AUTH_PROFILE_MODULE in your project '
  360
+                    'settings')
315 361
             try:
316 362
                 app_label, model_name = settings.AUTH_PROFILE_MODULE.split('.')
317 363
             except ValueError:
318  
-                raise SiteProfileNotAvailable('app_label and model_name should'
319  
-                        ' be separated by a dot in the AUTH_PROFILE_MODULE set'
320  
-                        'ting')
321  
-
  364
+                raise SiteProfileNotAvailable(
  365
+                    'app_label and model_name should be separated by a dot in '
  366
+                    'the AUTH_PROFILE_MODULE setting')
322 367
             try:
323 368
                 model = models.get_model(app_label, model_name)
324 369
                 if model is None:
325  
-                    raise SiteProfileNotAvailable('Unable to load the profile '
326  
-                        'model, check AUTH_PROFILE_MODULE in your project sett'
327  
-                        'ings')
328  
-                self._profile_cache = model._default_manager.using(self._state.db).get(user__id__exact=self.id)
  370
+                    raise SiteProfileNotAvailable(
  371
+                        'Unable to load the profile model, check '
  372
+                        'AUTH_PROFILE_MODULE in your project settings')
  373
+                self._profile_cache = model._default_manager.using(
  374
+                                   self._state.db).get(user__id__exact=self.id)
329 375
                 self._profile_cache.user = self
330 376
             except (ImportError, ImproperlyConfigured):
331 377
                 raise SiteProfileNotAvailable

0 notes on commit cb99b59

Please sign in to comment.
Something went wrong with that request. Please try again.