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 | |