Skip to content

Commit

Permalink
Fixed #13914 -- Added natural keys to User and Group models in auth c…
Browse files Browse the repository at this point in the history
…ontrib app. Thanks, jbochi and closedbracket.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@17429 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information
jezdez committed Feb 4, 2012
1 parent 6ecadcb commit 954e3b4
Show file tree
Hide file tree
Showing 6 changed files with 120 additions and 6 deletions.
32 changes: 32 additions & 0 deletions django/contrib/auth/fixtures/natural.json
@@ -0,0 +1,32 @@
[
{
"pk": 1,
"model": "auth.group",
"fields": {
"name": "my_group",
"permissions": []
}
},
{
"pk": 1,
"model": "auth.user",
"fields": {
"username": "my_username",
"first_name": "",
"last_name": "",
"is_active": true,
"is_superuser": true,
"is_staff": true,
"last_login": "2012-01-13 00:14:00",
"groups": [
[
"my_group"
]
],
"user_permissions": [],
"password": "pbkdf2_sha256$10000$LUyhxJjuLwXF$f6Zbpnx1L5dPze8m0itBaHMDyZ/n6JyhuavQy2RrBIM=",
"email": "email@example.com",
"date_joined": "2012-01-13 00:14:00"
}
}
]
30 changes: 30 additions & 0 deletions django/contrib/auth/fixtures/regular.json
@@ -0,0 +1,30 @@
[
{
"pk": 1,
"model": "auth.group",
"fields": {
"name": "my_group",
"permissions": []
}
},
{
"pk": 1,
"model": "auth.user",
"fields": {
"username": "my_username",
"first_name": "",
"last_name": "",
"is_active": true,
"is_superuser": true,
"is_staff": true,
"last_login": "2012-01-13 00:14:00",
"groups": [
1
],
"user_permissions": [],
"password": "pbkdf2_sha256$10000$LUyhxJjuLwXF$f6Zbpnx1L5dPze8m0itBaHMDyZ/n6JyhuavQy2RrBIM=",
"email": "email@example.com",
"date_joined": "2012-01-13 00:14:00"
}
}
]
18 changes: 18 additions & 0 deletions django/contrib/auth/models.py
Expand Up @@ -86,6 +86,13 @@ def natural_key(self):
natural_key.dependencies = ['contenttypes.contenttype']


class GroupManager(models.Manager):
"""
The manager for the auth's Group model.
"""
def get_by_natural_key(self, name):
return self.get(name=name)

class Group(models.Model):
"""
Groups are a generic way of categorizing users to apply permissions, or
Expand All @@ -107,13 +114,18 @@ class Group(models.Model):
permissions = models.ManyToManyField(Permission,
verbose_name=_('permissions'), blank=True)

objects = GroupManager()

class Meta:
verbose_name = _('group')
verbose_name_plural = _('groups')

def __unicode__(self):
return self.name

def natural_key(self):
return (self.name,)


class UserManager(models.Manager):
def create_user(self, username, email=None, password=None):
Expand Down Expand Up @@ -160,6 +172,9 @@ def make_random_password(self, length=10,
"""
return get_random_string(length, allowed_chars)

def get_by_natural_key(self, username):
return self.get(username=username)


# A few helper functions for common logic between User and AnonymousUser.
def _user_get_all_permissions(user, obj):
Expand Down Expand Up @@ -240,6 +255,9 @@ class Meta:
def __unicode__(self):
return self.username

def natural_key(self):
return (self.username,)

def get_absolute_url(self):
return "/users/%s/" % urllib.quote(smart_str(self.username))

Expand Down
7 changes: 4 additions & 3 deletions django/contrib/auth/tests/__init__.py
Expand Up @@ -10,12 +10,13 @@
from django.contrib.auth.tests.remote_user import (RemoteUserTest,
RemoteUserNoCreateTest, RemoteUserCustomTest)
from django.contrib.auth.tests.management import GetDefaultUsernameTestCase
from django.contrib.auth.tests.models import ProfileTestCase
from django.contrib.auth.tests.models import (ProfileTestCase, NaturalKeysTestCase,
LoadDataWithoutNaturalKeysTestCase, LoadDataWithNaturalKeysTestCase)
from django.contrib.auth.tests.hashers import TestUtilsHashPass
from django.contrib.auth.tests.signals import SignalTestCase
from django.contrib.auth.tests.tokens import TokenGeneratorTest
from django.contrib.auth.tests.views import (AuthViewNamedURLTests,
PasswordResetTest, ChangePasswordTest, LoginTest, LogoutTest,
from django.contrib.auth.tests.views import (AuthViewNamedURLTests,
PasswordResetTest, ChangePasswordTest, LoginTest, LogoutTest,
LoginURLSettings)

# The password for the fixture data users is 'password'
35 changes: 33 additions & 2 deletions django/contrib/auth/tests/models.py
@@ -1,6 +1,6 @@
from django.conf import settings
from django.test import TestCase
from django.contrib.auth.models import User, SiteProfileNotAvailable
from django.contrib.auth.models import Group, User, SiteProfileNotAvailable

class ProfileTestCase(TestCase):
fixtures = ['authtestdata.json']
Expand All @@ -26,10 +26,41 @@ def test_site_profile_not_available(self):
user = User.objects.get(username='testclient')
self.assertRaises(SiteProfileNotAvailable, user.get_profile)

# Bad syntax in AUTH_PROFILE_MODULE:
# Bad syntax in AUTH_PROFILE_MODULE:
settings.AUTH_PROFILE_MODULE = 'foobar'
self.assertRaises(SiteProfileNotAvailable, user.get_profile)

# module that doesn't exist
settings.AUTH_PROFILE_MODULE = 'foo.bar'
self.assertRaises(SiteProfileNotAvailable, user.get_profile)


class NaturalKeysTestCase(TestCase):
fixtures = ['authtestdata.json']

def test_user_natural_key(self):
staff_user = User.objects.get(username='staff')
self.assertEquals(User.objects.get_by_natural_key('staff'), staff_user)
self.assertEquals(staff_user.natural_key(), ('staff',))

def test_group_natural_key(self):
users_group = Group.objects.create(name='users')
self.assertEquals(Group.objects.get_by_natural_key('users'), users_group)


class LoadDataWithoutNaturalKeysTestCase(TestCase):
fixtures = ['regular.json']

def test_user_is_created_and_added_to_group(self):
user = User.objects.get(username='my_username')
group = Group.objects.get(name='my_group')
self.assertEquals(group, user.groups.get())


class LoadDataWithNaturalKeysTestCase(TestCase):
fixtures = ['natural.json']
def test_user_is_created_and_added_to_group(self):
user = User.objects.get(username='my_username')
group = Group.objects.get(name='my_group')
self.assertEquals(group, user.groups.get())

4 changes: 3 additions & 1 deletion docs/topics/serialization.txt
Expand Up @@ -215,7 +215,9 @@ automatically created by Django during the database synchronization process,
the primary key of a given content type isn't easy to predict; it will
depend on how and when :djadmin:`syncdb` was executed. This is true for all
models which automatically generate objects, notably including
:class:`~django.contrib.auth.models.Permission`.
:class:`~django.contrib.auth.models.Permission`,
:class:`~django.contrib.auth.models.Group`, and
:class:`~django.contrib.auth.models.User`.

.. warning::

Expand Down

0 comments on commit 954e3b4

Please sign in to comment.