Index: django/db/models/sql/query.py
===================================================================
--- django/db/models/sql/query.py	(revision 11479)
+++ django/db/models/sql/query.py	(working copy)
@@ -1441,6 +1441,36 @@
             self.fill_related_selections(f.rel.to._meta, alias, cur_depth + 1,
                     used, next, restricted, new_nullable, dupe_set, avoid)
 
+        # Do reverse columns, but only the ones in the requested list.
+        if restricted:
+            related_fields = [(x.field, x.model) for x in opts.get_all_related_objects() if x.field.unique]
+            for f, model in related_fields:
+                if f.rel.parent_link or f.related_query_name() not in requested:
+                    continue
+                table = model._meta.db_table
+                alias = self.join((root_alias, table, f.rel.get_related_field().column,
+                        f.column), exclusions=used,
+                        promote=True, reuse=used)
+                used.add(alias)
+
+                self.related_select_cols.extend([(alias, f2.column)
+                        for f2 in model._meta.fields])
+                self.related_select_fields.extend(model._meta.fields)
+
+                next = requested.get(f.related_query_name(), {})
+                #if nullable is not None:
+                #    new_nullable = nullable
+                #else:
+                #    new_nullable = f.null
+                if f.null is not None:
+                    new_nullable = f.null
+                else:
+                    new_nullable = None
+                self.fill_related_selections(model._meta, table, cur_depth + 1,
+                        used, next, restricted, new_nullable)
+
+
+
     def add_aggregate(self, aggregate, model, alias, is_summary):
         """
         Adds a single aggregate expression to the Query
@@ -1736,7 +1766,7 @@
                     raise FieldError("Cannot resolve keyword %r into field. "
                             "Choices are: %s" % (name, ", ".join(names)))
 
-            if not allow_many and (m2m or not direct):
+            if not allow_many and m2m:
                 for alias in joins:
                     self.unref_alias(alias)
                 raise MultiJoin(pos + 1)
Index: django/db/models/options.py
===================================================================
--- django/db/models/options.py	(revision 11479)
+++ django/db/models/options.py	(working copy)
@@ -47,6 +47,7 @@
         self.proxy_for_model = None
         self.parents = SortedDict()
         self.duplicate_targets = {}
+        self.reverse_field_cache = {}
 
         # To handle various inheritance situations, we need to track where
         # managers came from (concrete or abstract base classes).
Index: django/db/models/fields/related.py
===================================================================
--- django/db/models/fields/related.py	(revision 11479)
+++ django/db/models/fields/related.py	(working copy)
@@ -1,3 +1,4 @@
+import types
 from django.db import connection, transaction
 from django.db.backends import util
 from django.db.models import signals, get_model
@@ -179,7 +180,11 @@
     # SingleRelatedObjectDescriptor instance.
     def __init__(self, related):
         self.related = related
-        self.cache_name = '_%s_cache' % related.get_accessor_name()
+        #self.cache_name = '_%s_cache' % related.get_accessor_name()
+        cache_name = '_%s_cache' % related.field.related_query_name() 
+        # Contribute to the parent model for later lookup. 
+        related.parent_model._meta.reverse_field_cache[related.field.related_query_name()] = cache_name 
+        self.cache_name = cache_name 
 
     def __get__(self, instance, instance_type=None):
         if instance is None:
@@ -315,6 +320,11 @@
     # attribute is a ForeignRelatedObjectsDescriptor instance.
     def __init__(self, related):
         self.related = related   # RelatedObject instance
+        if related.field.unique: 
+            cache_name = '_%s_cache' % related.field.related_query_name() 
+            # Contribute to the parent model for later lookup. 
+            related.parent_model._meta.reverse_field_cache[related.field.related_query_name()] = cache_name 
+            self.cache_name = cache_name 
 
     def __get__(self, instance, instance_type=None):
         if instance is None:
@@ -333,6 +343,9 @@
         if self.related.field.null:
             manager.clear()
         manager.add(*value)
+        # Cache the value specially if from a unique set. 
+        if self.related.field.unique:
+            self.cache_name = value
 
     def delete_manager(self, instance):
         """
@@ -349,6 +362,8 @@
         """
         rel_field = self.related.field
         rel_model = self.related.model
+	if rel_field.unique:
+            cache_name = self.cache_name 
 
         class RelatedManager(superclass):
             def get_query_set(self):
@@ -393,6 +408,17 @@
                         obj.save()
                 clear.alters_data = True
 
+            if rel_field.unique:
+	        def all(self): 
+                    try: 
+                        result = getattr(instance, cache_name) 
+                        if isinstance(result, (types.TupleType, types.ListType)): 
+                            return result 
+                        else: 
+                            return [result] 
+                    except AttributeError, ae: 
+                        return superclass.get_query_set(self) 
+
         manager = RelatedManager()
         attname = rel_field.rel.get_related_field().name
         manager.core_filters = {'%s__%s' % (rel_field.name, attname):
Index: django/db/models/query.py
===================================================================
--- django/db/models/query.py	(revision 11479)
+++ django/db/models/query.py	(working copy)
@@ -987,6 +987,7 @@
             obj = klass(*fields)
 
     index_end = index_start + field_count + offset
+
     for f in klass._meta.fields:
         if not select_related_descend(f, restricted, requested):
             continue
@@ -1000,6 +1001,30 @@
             rel_obj, index_end = cached_row
             if obj is not None:
                 setattr(obj, f.get_cache_name(), rel_obj)
+
+            # Do the reverse cache if the field is a unique relation.
+            if f.unique:
+                cache_var_name = rel_obj._meta.reverse_field_cache[f.related_query_name()]
+                setattr(rel_obj, cache_var_name, obj)
+
+    if restricted:
+        related_fields = [(x.field, x.model) for x in klass._meta.get_all_related_objects() if x.field.unique]
+        for f, model in related_fields:
+            if f.related_query_name() not in requested:
+                continue
+
+            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 rel_obj is not None:
+                    setattr(rel_obj, f.get_cache_name(), obj)
+
+                # Now do the reverse cache.
+                cache_var_name = obj._meta.reverse_field_cache[f.related_query_name()]
+                setattr(obj, cache_var_name, rel_obj)
+
     return obj, index_end
 
 def delete_objects(seen_objs):
Index: tests/modeltests/select_related_onetoone/__init__.py
===================================================================
Index: tests/modeltests/select_related_onetoone/models.py
===================================================================
--- tests/modeltests/select_related_onetoone/models.py	(revision 0)
+++ tests/modeltests/select_related_onetoone/models.py	(revision 0)
@@ -0,0 +1,54 @@
+from django.db import models
+from django import db
+
+class User(models.Model):
+    username = models.CharField(max_length=100)
+    email = models.CharField(max_length=100)
+    def __unicode__(self):
+        return self.username
+
+class UserProfile(models.Model):
+    user = models.OneToOneField(User, related_name='userprofile')
+    city = models.CharField(max_length=100)
+    state = models.CharField(max_length=2)
+
+    def __unicode__(self):
+        return '%s, %s' % (self.city, self.state)
+
+
+__test__ = {'API_TESTS':"""
+>>> from django.conf import settings
+>>> settings.DEBUG = True
+
+>>> user = User.objects.create(username='test')
+>>> userprofile = UserProfile.objects.create(user=user,state='KS',city='Lawrence')
+>>> user
+<User: test>
+>>> user.userprofile
+<UserProfile: Lawrence, KS>
+
+# select_related works as usual, using forward relationship
+>>> db.reset_queries()
+>>> u = UserProfile.objects.select_related('user').get(state='KS')
+>>> u.user.username
+u'test'
+>>> len(db.connection.queries)
+1
+
+# Now we can select reverse from the user to userprofile
+>>> db.reset_queries()
+>>> u = User.objects.select_related('userprofile').get(username='test')
+>>> u.userprofile.state
+u'KS'
+>>> len(db.connection.queries)
+1
+
+# Also test w/ values()
+>>> db.reset_queries()
+>>> User.objects.values('username', 'userprofile__state')
+[{'username': u'test', 'userprofile__state': u'KS'}]
+>>> len(db.connection.queries)
+1
+
+settings.DEBUG = False
+"""}
