Browse Source

Fixed #13914 -- Added natural keys to User and Group models in auth contrib app. Thanks, jbochi and closedbracket.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@17429 bcc190cf-cafb-0310-a4f2-bffc1f526a37
Jannis Leidel 13 years ago
parent
commit
954e3b4ad3

+ 32 - 0
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 - 0
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 - 0
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))
 

+ 4 - 3
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'

+ 33 - 2
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())
+

+ 3 - 1
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::