diff --git a/django/contrib/auth/fixtures/natural.json b/django/contrib/auth/fixtures/natural.json new file mode 100644 index 00000000000..795c1a3b7aa --- /dev/null +++ b/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" + } + } +] diff --git a/django/contrib/auth/fixtures/regular.json b/django/contrib/auth/fixtures/regular.json new file mode 100644 index 00000000000..dad891df2c6 --- /dev/null +++ b/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" + } + } +] diff --git a/django/contrib/auth/models.py b/django/contrib/auth/models.py index 8064a4eb349..571bf7902c1 100644 --- a/django/contrib/auth/models.py +++ b/django/contrib/auth/models.py @@ -86,6 +86,13 @@ class Permission(models.Model): 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 @@ -107,6 +114,8 @@ class Group(models.Model): permissions = models.ManyToManyField(Permission, verbose_name=_('permissions'), blank=True) + objects = GroupManager() + class Meta: verbose_name = _('group') verbose_name_plural = _('groups') @@ -114,6 +123,9 @@ class Group(models.Model): 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): @@ -160,6 +172,9 @@ class UserManager(models.Manager): """ 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): @@ -240,6 +255,9 @@ class User(models.Model): 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)) diff --git a/django/contrib/auth/tests/__init__.py b/django/contrib/auth/tests/__init__.py index 883e4c944b5..e7188c0e4ca 100644 --- a/django/contrib/auth/tests/__init__.py +++ b/django/contrib/auth/tests/__init__.py @@ -10,12 +10,13 @@ from django.contrib.auth.tests.forms import (UserCreationFormTest, 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' diff --git a/django/contrib/auth/tests/models.py b/django/contrib/auth/tests/models.py index 754c6db7b42..b48da4b42e2 100644 --- a/django/contrib/auth/tests/models.py +++ b/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'] @@ -26,10 +26,41 @@ class ProfileTestCase(TestCase): 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()) + diff --git a/docs/topics/serialization.txt b/docs/topics/serialization.txt index 244609337a3..d7d72ec48a8 100644 --- a/docs/topics/serialization.txt +++ b/docs/topics/serialization.txt @@ -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::