diff --git a/django/contrib/auth/models.py b/django/contrib/auth/models.py
index ec3af63..8d95de6 100644
a
|
b
|
class Permission(models.Model):
|
94 | 94 | return (self.codename,) + self.content_type.natural_key() |
95 | 95 | natural_key.dependencies = ['contenttypes.contenttype'] |
96 | 96 | |
| 97 | class GroupManager(models.Manager): |
| 98 | def get_by_natural_key(self, name): |
| 99 | return self.get(name=name) |
| 100 | |
97 | 101 | class Group(models.Model): |
98 | 102 | """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. |
99 | 103 | |
… |
… |
class Group(models.Model):
|
103 | 107 | """ |
104 | 108 | name = models.CharField(_('name'), max_length=80, unique=True) |
105 | 109 | permissions = models.ManyToManyField(Permission, verbose_name=_('permissions'), blank=True) |
| 110 | objects = GroupManager() |
106 | 111 | |
107 | 112 | class Meta: |
108 | 113 | verbose_name = _('group') |
… |
… |
class Group(models.Model):
|
111 | 116 | def __unicode__(self): |
112 | 117 | return self.name |
113 | 118 | |
| 119 | def natural_key(self): |
| 120 | return (self.name,) |
| 121 | |
114 | 122 | class UserManager(models.Manager): |
115 | 123 | def create_user(self, username, email, password=None): |
116 | 124 | """ |
… |
… |
class UserManager(models.Manager):
|
150 | 158 | from random import choice |
151 | 159 | return ''.join([choice(allowed_chars) for i in range(length)]) |
152 | 160 | |
| 161 | def get_by_natural_key(self, username): |
| 162 | return self.get(username=username) |
| 163 | |
153 | 164 | |
154 | 165 | # A few helper functions for common logic between User and AnonymousUser. |
155 | 166 | def _user_get_all_permissions(user, obj): |
… |
… |
class User(models.Model):
|
393 | 404 | return self._message_set |
394 | 405 | message_set = property(_get_message_set) |
395 | 406 | |
| 407 | def natural_key(self): |
| 408 | return (self.username,) |
| 409 | |
396 | 410 | class Message(models.Model): |
397 | 411 | """ |
398 | 412 | The message system is a lightweight way to queue messages for given |
diff --git a/django/contrib/auth/tests/__init__.py b/django/contrib/auth/tests/__init__.py
index 3a8f55b..9dda8e2 100644
a
|
b
|
from django.contrib.auth.tests.forms import (UserCreationFormTest,
|
8 | 8 | UserChangeFormTest, PasswordResetFormTest) |
9 | 9 | from django.contrib.auth.tests.remote_user import (RemoteUserTest, |
10 | 10 | RemoteUserNoCreateTest, RemoteUserCustomTest) |
11 | | from django.contrib.auth.tests.models import ProfileTestCase |
| 11 | from django.contrib.auth.tests.models import ProfileTestCase, NaturalKeysTestCase |
12 | 12 | from django.contrib.auth.tests.signals import SignalTestCase |
13 | 13 | from django.contrib.auth.tests.tokens import TokenGeneratorTest |
14 | 14 | from django.contrib.auth.tests.views import (PasswordResetTest, |
diff --git a/django/contrib/auth/tests/models.py b/django/contrib/auth/tests/models.py
index 754c6db..925ed7d 100644
a
|
b
|
|
1 | 1 | from django.conf import settings |
2 | 2 | from django.test import TestCase |
3 | | from django.contrib.auth.models import User, SiteProfileNotAvailable |
| 3 | from django.contrib.auth.models import Group, User, SiteProfileNotAvailable |
4 | 4 | |
5 | 5 | class ProfileTestCase(TestCase): |
6 | 6 | fixtures = ['authtestdata.json'] |
… |
… |
class ProfileTestCase(TestCase):
|
33 | 33 | # module that doesn't exist |
34 | 34 | settings.AUTH_PROFILE_MODULE = 'foo.bar' |
35 | 35 | self.assertRaises(SiteProfileNotAvailable, user.get_profile) |
| 36 | |
| 37 | |
| 38 | class NaturalKeysTestCase(TestCase): |
| 39 | fixtures = ['authtestdata.json'] |
| 40 | def test_user_natural_key(self): |
| 41 | staff_user = User.objects.get(username='staff') |
| 42 | self.assertEquals(User.objects.get_by_natural_key('staff'), staff_user) |
| 43 | self.assertEquals(staff_user.natural_key(), ('staff',)) |
| 44 | |
| 45 | def test_group_natural_key(self): |
| 46 | users_group = Group.objects.create(name='users') |
| 47 | self.assertEquals(Group.objects.get_by_natural_key('users'), users_group) |
diff --git a/docs/topics/serialization.txt b/docs/topics/serialization.txt
index c8acc85..f506f20 100644
a
|
b
|
dependency, we add one extra line::
|
400 | 400 | This definition ensures that ``ContentType`` models are serialized before |
401 | 401 | ``Permission`` models. In turn, any object referencing ``Permission`` will |
402 | 402 | be serialized after both ``ContentType`` and ``Permission``. |
| 403 | |
| 404 | .. note:: |
| 405 | |
| 406 | Besides the ``Permission`` model, both ``User`` and ``Group`` models |
| 407 | in ``contrib.auth`` support natural keys. |
| 408 | |