diff --git a/django/db/models/fields/related.py b/django/db/models/fields/related.py
index 8fec836..8e27244 100644
--- a/django/db/models/fields/related.py
+++ b/django/db/models/fields/related.py
@@ -188,7 +188,7 @@ class SingleRelatedObjectDescriptor(object):
     # SingleRelatedObjectDescriptor instance.
     def __init__(self, related):
         self.related = related
-        self.cache_name = '_%s_cache' % related.get_accessor_name()
+        self.cache_name = related.get_accessor_cache()
 
     def __get__(self, instance, instance_type=None):
         if instance is None:
@@ -307,7 +307,7 @@ class ReverseSingleRelatedObjectDescriptor(object):
             # cache. This cache also might not exist if the related object
             # hasn't been accessed yet.
             if related:
-                cache_name = '_%s_cache' % self.field.related.get_accessor_name()
+                cache_name = self.field.related.get_accessor_cache()
                 try:
                     delattr(related, cache_name)
                 except AttributeError:
diff --git a/django/db/models/query.py b/django/db/models/query.py
index 4e3326a..afbcc24 100644
--- a/django/db/models/query.py
+++ b/django/db/models/query.py
@@ -1147,6 +1147,24 @@ def get_cached_row(klass, row, index_start, max_depth=0, cur_depth=0,
             rel_obj, index_end = cached_row
             if obj is not None:
                 setattr(obj, f.get_cache_name(), rel_obj)
+            if f.unique:
+                setattr(rel_obj, f.related.get_accessor_cache(), obj)
+
+    if restricted:
+        related_fields = [(o.field, o.model) for o in klass._meta.get_all_related_objects()
+            if o.field.unique and o.field.related_query_name() in requested]
+        for f, model in related_fields:
+            next = requested.get(f.related_query_name(), {})
+            cached_row = get_cached_row(model, row, index_end, max_depth,
+                cur_depth+1, next)
+            if cached_row:
+                rel_obj, index_end = cached_row
+                if obj is not None:
+                    setattr(obj, f.related.get_accessor_cache(), rel_obj)
+                if rel_obj is not None:
+                    setattr(rel_obj, f.get_cache_name(), obj)
+
+
     return obj, index_end
 
 def delete_objects(seen_objs, using):
diff --git a/django/db/models/related.py b/django/db/models/related.py
index afdf3f7..54258ca 100644
--- a/django/db/models/related.py
+++ b/django/db/models/related.py
@@ -45,3 +45,6 @@ class RelatedObject(object):
             return self.field.rel.related_name or (self.opts.object_name.lower() + '_set')
         else:
             return self.field.rel.related_name or (self.opts.object_name.lower())
+
+    def get_accessor_cache(self):
+        return "_%s_cache" % self.get_accessor_name()
diff --git a/django/db/models/sql/compiler.py b/django/db/models/sql/compiler.py
index 6a95d32..99d4c7e 100644
--- a/django/db/models/sql/compiler.py
+++ b/django/db/models/sql/compiler.py
@@ -520,7 +520,7 @@ class SQLCompiler(object):
 
         # Setup for the case when only particular related fields should be
         # included in the related selection.
-        if requested is None and restricted is not False:
+        if requested is None:
             if isinstance(self.query.select_related, dict):
                 requested = self.query.select_related
                 restricted = True
@@ -600,6 +600,57 @@ class SQLCompiler(object):
             self.fill_related_selections(f.rel.to._meta, alias, cur_depth + 1,
                     used, next, restricted, new_nullable, dupe_set, avoid)
 
+        if restricted and requested is not None:
+            related_fields = [(o.field, o.model) for o in opts.get_all_related_objects()
+                if o.field.unique and o.field.related_query_name() in requested
+            ]
+            for f, model in related_fields:
+                table = model._meta.db_table
+                int_opts = opts
+                alias = root_alias
+                alias_chain = []
+                chain = opts.get_base_chain(f.rel.to)
+                avoid = avoid_set.copy()
+                if chain is not None:
+                    for int_model in chain:
+                        if not int_opts.parents[int_model]:
+                            int_opts = int_model._meta
+                            continue
+                        lhs_col = int_opts.parents[int_model].column
+                        dedupe = lhs_col in opts.duplicate_targets
+                        if dedupe:
+                            avoid.update(self.query.dupe_avoidance.get(id(opts), lhs_col), ())
+                            dupe_set.add((opts, lhs_col))
+                        int_opts = int_model._meta
+                        alias = self.query.join(
+                            (alias, int_opts.db_table, lhs_col, int_opts.pk.column),
+                            exclusions=used, promote=True, reuse=used
+                        )
+                        alias_chain.append(alias)
+                        for dupe_opts, dupe_col in dupe_set:
+                            self.query.update_dupe_avoidance(dupe_opts, dupe_col, alias)
+                    dedupe = f.column in opts.duplicate_targets
+                    if dupe_set or dedupe:
+                        avoid.update(self.query.dupe_avoidance.get((id(opts), f.column), ()))
+                        if dedupe:
+                            dupe_set.add((opts, f.column))
+                alias = self.query.join(
+                    (alias, table, f.rel.get_related_field().column, f.column),
+                    exclusions=used.union(avoid),
+                    promote=True
+                )
+                used.add(alias)
+                columns, aliases = self.get_default_columns(start_alias=alias,
+                    opts=model._meta, as_pairs=True)
+                self.query.related_select_cols.extend(columns)
+                self.query.related_select_fields.extend(model._meta.fields)
+
+                next = requested.get(f.related_query_name(), {})
+                new_nullable = f.null or None
+
+                self.fill_related_selections(model._meta, table, cur_depth+1,
+                    used, next, restricted, new_nullable)
+
     def deferred_to_columns(self):
         """
         Converts the self.deferred_loading data structure to mapping of table
diff --git a/tests/regressiontests/select_related_onetoone/__init__.py b/tests/regressiontests/select_related_onetoone/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/tests/regressiontests/select_related_onetoone/models.py b/tests/regressiontests/select_related_onetoone/models.py
new file mode 100644
index 0000000..05efadf
--- /dev/null
+++ b/tests/regressiontests/select_related_onetoone/models.py
@@ -0,0 +1,44 @@
+from django.db import models
+
+
+class User(models.Model):
+    username = models.CharField(max_length=100)
+    email = models.EmailField()
+
+    def __unicode__(self):
+        return self.username
+
+
+class UserProfile(models.Model):
+    user = models.OneToOneField(User)
+    city = models.CharField(max_length=100)
+    state = models.CharField(max_length=2)
+
+    def __unicode__(self):
+        return "%s, %s" % (self.city, self.state)
+
+
+class UserStatResult(models.Model):
+    results = models.CharField(max_length=50)
+
+    def __unicode__(self):
+        return 'UserStatResults, results = %s' % (self.results,)
+    
+
+class UserStat(models.Model):
+    user = models.OneToOneField(User, primary_key=True)
+    posts = models.IntegerField()
+    results = models.ForeignKey(UserStatResult)
+
+    def __unicode__(self):
+        return 'UserStat, posts = %s' % (self.posts,)
+
+class StatDetails(models.Model):
+    base_stats = models.OneToOneField(UserStat)
+    comments = models.IntegerField()
+
+    def __unicode__(self):
+        return 'StatDetails, comments = %s' % (self.comments,)
+
+class AdvancedUserStat(UserStat):
+    pass
diff --git a/tests/regressiontests/select_related_onetoone/tests.py b/tests/regressiontests/select_related_onetoone/tests.py
new file mode 100644
index 0000000..08e798b
--- /dev/null
+++ b/tests/regressiontests/select_related_onetoone/tests.py
@@ -0,0 +1,81 @@
+from django import db
+from django.conf import settings
+from django.test import TestCase
+
+from models import User, UserProfile, UserStat, UserStatResult, StatDetails, AdvancedUserStat
+
+class ReverseSelectRelatedTestCase(TestCase):
+    def setUp(self):
+        self.old_debug = settings.DEBUG
+        settings.DEBUG = True
+
+        user = User.objects.create(username="test")
+        userprofile = UserProfile.objects.create(user=user, state="KS",
+                                                 city="Lawrence")
+        results = UserStatResult.objects.create(results='first results')
+        userstat = UserStat.objects.create(user=user, posts=150,
+                                           results=results)
+        details = StatDetails.objects.create(base_stats=userstat, comments=259)
+
+        user2 = User.objects.create(username="bob")
+        results2 = UserStatResult.objects.create(results='moar results')
+        advstat = AdvancedUserStat.objects.create(user=user2, posts=200,
+                                                  results=results2)
+        StatDetails.objects.create(base_stats=advstat, comments=250)
+
+        db.reset_queries()
+
+    def assertQueries(self, queries):
+        self.assertEqual(len(db.connection.queries), queries)
+
+    def tearDown(self):
+        settings.DEBUG = self.old_debug
+
+    def test_basic(self):
+        u = User.objects.select_related("userprofile").get(username="test")
+        self.assertEqual(u.userprofile.state, "KS")
+        self.assertQueries(1)
+
+    def test_follow_next_level(self):
+        u = User.objects.select_related("userstat__results").get(username="test")
+        self.assertEqual(u.userstat.posts, 150)
+        self.assertEqual(u.userstat.results.results, 'first results')
+        self.assertQueries(1)
+
+    def test_follow_two(self):
+        u = User.objects.select_related("userprofile", "userstat").get(username="test")
+        self.assertEqual(u.userprofile.state, "KS")
+        self.assertEqual(u.userstat.posts, 150)
+        self.assertQueries(1)
+
+    def test_follow_two_next_level(self):
+        u = User.objects.select_related("userstat__results", "userstat__statdetails").get(username="test")
+        self.assertEqual(u.userstat.results.results, 'first results')
+        self.assertEqual(u.userstat.statdetails.comments, 259)
+        self.assertQueries(1)
+
+    def test_forward_and_back(self):
+        stat = UserStat.objects.select_related("user__userprofile").get(user__username="test")
+        self.assertEqual(stat.user.userprofile.state, 'KS')
+        self.assertEqual(stat.user.userstat.posts, 150)
+        self.assertQueries(1)
+
+    def test_back_and_forward(self):
+        u = User.objects.select_related("userstat").get(username="test")
+        self.assertEqual(u.userstat.user.username, 'test')
+        self.assertQueries(1)
+
+    def test_not_followed_by_default(self):
+        u = User.objects.select_related().get(username="test")
+        self.assertEqual(u.userstat.posts, 150)
+        self.assertQueries(2)
+
+    def test_follow_from_child_class(self):
+        stat = AdvancedUserStat.objects.select_related("statdetails").get(posts=200)
+        self.assertEqual(stat.statdetails.comments, 250)
+        self.assertQueries(1)
+
+    def test_follow_inheritance(self):
+        stat = UserStat.objects.select_related('advanceduserstat').get(posts=200)
+        self.assertEqual(stat.advanceduserstat.posts, 200)
+        self.assertQueries(1)
