Index: docs/topics/serialization.txt
===================================================================
--- docs/topics/serialization.txt	(revision 17370)
+++ docs/topics/serialization.txt	(working copy)
@@ -215,7 +215,7 @@
 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::
 
Index: django/contrib/auth/tests/__init__.py
===================================================================
--- django/contrib/auth/tests/__init__.py	(revision 17370)
+++ django/contrib/auth/tests/__init__.py	(working copy)
@@ -10,7 +10,8 @@
 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
Index: django/contrib/auth/tests/models.py
===================================================================
--- django/contrib/auth/tests/models.py	(revision 17370)
+++ django/contrib/auth/tests/models.py	(working copy)
@@ -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']
@@ -33,3 +33,32 @@
         # 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())
+
Index: django/contrib/auth/fixtures/regular.json
===================================================================
--- django/contrib/auth/fixtures/regular.json	(revision 0)
+++ django/contrib/auth/fixtures/regular.json	(revision 0)
@@ -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"
+        }
+    }
+]
Index: django/contrib/auth/fixtures/natural.json
===================================================================
--- django/contrib/auth/fixtures/natural.json	(revision 0)
+++ django/contrib/auth/fixtures/natural.json	(revision 0)
@@ -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"
+        }
+    }
+]
Index: django/contrib/auth/models.py
===================================================================
--- django/contrib/auth/models.py	(revision 17370)
+++ django/contrib/auth/models.py	(working copy)
@@ -86,6 +86,10 @@
     natural_key.dependencies = ['contenttypes.contenttype']
 
 
+class GroupManager(models.Manager):
+    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
@@ -104,6 +108,7 @@
     messages.
     """
     name = models.CharField(_('name'), max_length=80, unique=True)
+    objects = GroupManager()
     permissions = models.ManyToManyField(Permission,
         verbose_name=_('permissions'), blank=True)
 
@@ -114,7 +119,10 @@
     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,7 +168,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):
     permissions = set()
@@ -240,6 +251,9 @@
     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))
 
