diff -r e165fea06e06 django/contrib/auth/models.py
--- a/django/contrib/auth/models.py	Thu Jan 14 17:43:46 2010 +0000
+++ b/django/contrib/auth/models.py	Tue Jan 19 23:17:54 2010 +0800
@@ -3,7 +3,7 @@
 
 from django.contrib import auth
 from django.core.exceptions import ImproperlyConfigured
-from django.db import models, DEFAULT_DB_ALIAS
+from django.db import models
 from django.db.models.manager import EmptyManager
 from django.contrib.contenttypes.models import ContentType
 from django.utils.encoding import smart_str
diff -r e165fea06e06 django/contrib/contenttypes/generic.py
--- a/django/contrib/contenttypes/generic.py	Thu Jan 14 17:43:46 2010 +0000
+++ b/django/contrib/contenttypes/generic.py	Tue Jan 19 23:17:54 2010 +0800
@@ -5,7 +5,7 @@
 from django.core.exceptions import ObjectDoesNotExist
 from django.db import connection
 from django.db.models import signals
-from django.db import models, DEFAULT_DB_ALIAS
+from django.db import models
 from django.db.models.fields.related import RelatedField, Field, ManyToManyRel
 from django.db.models.loading import get_model
 from django.forms import ModelForm
@@ -255,7 +255,7 @@
                     raise TypeError("'%s' instance expected" % self.model._meta.object_name)
                 setattr(obj, self.content_type_field_name, self.content_type)
                 setattr(obj, self.object_id_field_name, self.pk_val)
-                obj.save(using=self.instance._state.db)
+                obj.save()
         add.alters_data = True
 
         def remove(self, *objs):
diff -r e165fea06e06 django/contrib/contenttypes/models.py
--- a/django/contrib/contenttypes/models.py	Thu Jan 14 17:43:46 2010 +0000
+++ b/django/contrib/contenttypes/models.py	Tue Jan 19 23:17:54 2010 +0800
@@ -1,4 +1,4 @@
-from django.db import models, DEFAULT_DB_ALIAS
+from django.db import models
 from django.utils.translation import ugettext_lazy as _
 from django.utils.encoding import smart_unicode
 
diff -r e165fea06e06 django/contrib/gis/db/models/sql/query.py
--- a/django/contrib/gis/db/models/sql/query.py	Thu Jan 14 17:43:46 2010 +0000
+++ b/django/contrib/gis/db/models/sql/query.py	Tue Jan 19 23:17:54 2010 +0800
@@ -1,4 +1,4 @@
-from django.db import connections, DEFAULT_DB_ALIAS
+from django.db import connections
 from django.db.models.query import sql
 
 from django.contrib.gis.db.models.fields import GeometryField
diff -r e165fea06e06 django/db/models/base.py
--- a/django/db/models/base.py	Thu Jan 14 17:43:46 2010 +0000
+++ b/django/db/models/base.py	Tue Jan 19 23:17:54 2010 +0800
@@ -439,7 +439,7 @@
         need for overrides of save() to pass around internal-only parameters
         ('raw', 'cls', and 'origin').
         """
-        using = using or self._state.db or DEFAULT_DB_ALIAS
+        using = using or self._default_manager._db_for_write(self)
         connection = connections[using]
         assert not (force_insert and force_update)
         if cls is None:
@@ -592,7 +592,7 @@
             parent_obj._collect_sub_objects(seen_objs)
 
     def delete(self, using=None):
-        using = using or self._state.db or DEFAULT_DB_ALIAS
+        using = using or self._default_manager._db_for_write(self)
         connection = connections[using]
         assert self._get_pk_val() is not None, "%s object can't be deleted because its %s attribute is set to None." % (self._meta.object_name, self._meta.pk.attname)
 
@@ -719,7 +719,7 @@
                     # no value, skip the lookup
                     continue
                 if f.primary_key and not getattr(self, '_adding', False):
-                    # no need to check for unique primary key when editting 
+                    # no need to check for unique primary key when editing
                     continue
                 lookup_kwargs[str(field_name)] = lookup_value
 
diff -r e165fea06e06 django/db/models/fields/related.py
--- a/django/db/models/fields/related.py	Thu Jan 14 17:43:46 2010 +0000
+++ b/django/db/models/fields/related.py	Tue Jan 19 23:17:54 2010 +0800
@@ -1,3 +1,4 @@
+from django.conf import settings
 from django.db import connection, transaction, DEFAULT_DB_ALIAS
 from django.db.backends import util
 from django.db.models import signals, get_model
@@ -218,6 +219,16 @@
             raise ValueError('Cannot assign "%r": "%s.%s" must be a "%s" instance.' %
                                 (value, instance._meta.object_name,
                                  self.related.get_accessor_name(), self.related.opts.object_name))
+        elif value is not None:
+            if instance._state.db is None:
+                instance._state.db = instance._default_manager._db_for_write(value)
+            elif value._state.db is None:
+                value._state.db = value._default_manager._db_for_write(instance)
+            elif value._state.db is not None and instance._state.db is not None:
+                if (settings.DATABASES[value._default_manager._db_for_write(instance)]['SOURCE']
+                        != settings.DATABASES[value._state.db]['SOURCE']):
+                    raise ValueError('Cannot assign "%r": instance is on database "%s", value is is on database "%s"' %
+                                        (value, instance._state.db, value._state.db))
 
         # Set the value of the related field to the value of the related object's related field
         setattr(value, self.related.field.attname, getattr(instance, self.related.field.rel.get_related_field().attname))
@@ -260,7 +271,7 @@
             # If the related manager indicates that it should be used for
             # related fields, respect that.
             rel_mgr = self.field.rel.to._default_manager
-            using = instance._state.db or DEFAULT_DB_ALIAS
+            using = rel_mgr._db_for_read(instance)
             if getattr(rel_mgr, 'use_for_related_fields', False):
                 rel_obj = rel_mgr.using(using).get(**params)
             else:
@@ -281,14 +292,16 @@
             raise ValueError('Cannot assign "%r": "%s.%s" must be a "%s" instance.' %
                                 (value, instance._meta.object_name,
                                  self.field.name, self.field.rel.to._meta.object_name))
-        elif value is not None and value._state.db != instance._state.db:
+        elif value is not None:
             if instance._state.db is None:
-                instance._state.db = value._state.db
-            else:#elif value._state.db is None:
-                value._state.db = instance._state.db
-#            elif value._state.db is not None and instance._state.db is not None:
-#                raise ValueError('Cannot assign "%r": instance is on database "%s", value is is on database "%s"' %
-#                                    (value, instance._state.db, value._state.db))
+                instance._state.db = instance._default_manager._db_for_write(value)
+            elif value._state.db is None:
+                value._state.db = value._default_manager._db_for_write(instance)
+            elif value._state.db is not None and instance._state.db is not None:
+                if (settings.DATABASES[value._default_manager._db_for_write(instance)]['SOURCE']
+                        != settings.DATABASES[value._state.db]['SOURCE']):
+                    raise ValueError('Cannot assign "%r": instance is on database "%s", value is is on database "%s"' %
+                                        (value, instance._state.db, value._state.db))
 
         # If we're setting the value of a OneToOneField to None, we need to clear
         # out the cache on any old related object. Otherwise, deleting the
@@ -370,7 +383,7 @@
 
         class RelatedManager(superclass):
             def get_query_set(self):
-                using = instance._state.db or DEFAULT_DB_ALIAS
+                using = rel_model._default_manager._db_for_read(instance)
                 return superclass.get_query_set(self).using(using).filter(**(self.core_filters))
 
             def add(self, *objs):
@@ -378,7 +391,7 @@
                     if not isinstance(obj, self.model):
                         raise TypeError("'%s' instance expected" % self.model._meta.object_name)
                     setattr(obj, rel_field.name, instance)
-                    obj.save(using=instance._state.db)
+                    obj.save()
             add.alters_data = True
 
             def create(self, **kwargs):
@@ -390,7 +403,7 @@
                 # Update kwargs with the related object that this
                 # ForeignRelatedObjectsDescriptor knows about.
                 kwargs.update({rel_field.name: instance})
-                using = instance._state.db or DEFAULT_DB_ALIAS
+                using = rel_model._default_manager._db_for_write(instance)
                 return super(RelatedManager, self).using(using).get_or_create(**kwargs)
             get_or_create.alters_data = True
 
@@ -402,7 +415,7 @@
                         # Is obj actually part of this descriptor set?
                         if getattr(obj, rel_field.attname) == val:
                             setattr(obj, rel_field.name, None)
-                            obj.save(using=instance._state.db)
+                            obj.save()
                         else:
                             raise rel_field.rel.to.DoesNotExist("%r is not related to %r." % (obj, instance))
                 remove.alters_data = True
@@ -410,7 +423,7 @@
                 def clear(self):
                     for obj in self.all():
                         setattr(obj, rel_field.name, None)
-                        obj.save(using=instance._state.db)
+                        obj.save()
                 clear.alters_data = True
 
         manager = RelatedManager()
@@ -505,23 +518,26 @@
                 new_ids = set()
                 for obj in objs:
                     if isinstance(obj, self.model):
-#                        if obj._state.db != self.instance._state.db:
-#                            raise ValueError('Cannot add "%r": instance is on database "%s", value is is on database "%s"' %
-#                                                (obj, self.instance._state.db, obj._state.db))
+                        if (settings.DATABASES[obj._default_manager._db_for_write(self.instance)]['SOURCE']
+                               != settings.DATABASES[obj._state.db]['SOURCE']):
+                           raise ValueError('Cannot add "%r": instance is on database "%s", value is is on database "%s"' %
+                                               (obj, self.instance._state.db, obj._state.db))
                         new_ids.add(obj.pk)
                     elif isinstance(obj, Model):
                         raise TypeError("'%s' instance expected" % self.model._meta.object_name)
                     else:
                         new_ids.add(obj)
-                vals = self.through._default_manager.using(self.instance._state.db).values_list(target_field_name, flat=True)
+                db = self.instance._default_manager._db_for_read(self.instance)
+                vals = self.through._default_manager.using(db).values_list(target_field_name, flat=True)
                 vals = vals.filter(**{
                     source_field_name: self._pk_val,
                     '%s__in' % target_field_name: new_ids,
                 })
                 new_ids = new_ids - set(vals)
                 # Add the ones that aren't there already
+                db = self.instance._default_manager._db_for_write(self.instance)
                 for obj_id in new_ids:
-                    self.through._default_manager.using(self.instance._state.db).create(**{
+                    self.through._default_manager.using(db).create(**{
                         '%s_id' % source_field_name: self._pk_val,
                         '%s_id' % target_field_name: obj_id,
                     })
diff -r e165fea06e06 django/db/models/manager.py
--- a/django/db/models/manager.py	Thu Jan 14 17:43:46 2010 +0000
+++ b/django/db/models/manager.py	Tue Jan 19 23:17:54 2010 +0800
@@ -1,5 +1,5 @@
 from django.utils import copycompat as copy
-
+from django.conf import settings
 from django.db import DEFAULT_DB_ALIAS
 from django.db.models.query import QuerySet, EmptyQuerySet, insert_query, RawQuerySet
 from django.db.models import signals
@@ -87,30 +87,35 @@
         mgr._inherited = True
         return mgr
 
-    def db_manager(self, alias):
+    def db_manager(self, using):
         obj = copy.copy(self)
-        obj._db = alias
+        obj._db = using
         return obj
 
     @property
     def db(self):
-        return self._db or DEFAULT_DB_ALIAS
+        return self._db
+
+    def _db_for_write(self, instance):
+        if instance._state.db:
+            return settings.DATABASES[instance._state.db]['SOURCE'] or DEFAULT_DB_ALIAS
+        return DEFAULT_DB_ALIAS
+
+    def _db_for_read(self, instance):
+        return instance._state.db or DEFAULT_DB_ALIAS
 
     #######################
     # PROXIES TO QUERYSET #
     #######################
 
     def get_empty_query_set(self):
-        return EmptyQuerySet(self.model)
+        return EmptyQuerySet(self.model, using=self.db)
 
     def get_query_set(self):
         """Returns a new QuerySet object.  Subclasses can override this method
         to easily customize the behavior of the Manager.
         """
-        qs = QuerySet(self.model)
-        if self._db is not None:
-            qs = qs.using(self._db)
-        return qs
+        return QuerySet(self.model, using=self.db)
 
     def none(self):
         return self.get_empty_query_set()
diff -r e165fea06e06 django/db/models/query.py
--- a/django/db/models/query.py	Thu Jan 14 17:43:46 2010 +0000
+++ b/django/db/models/query.py	Tue Jan 19 23:17:54 2010 +0800
@@ -988,8 +988,8 @@
 
 
 class EmptyQuerySet(QuerySet):
-    def __init__(self, model=None, query=None):
-        super(EmptyQuerySet, self).__init__(model, query)
+    def __init__(self, model=None, query=None, using=None):
+        super(EmptyQuerySet, self).__init__(model, query, using)
         self._result_cache = []
 
     def __and__(self, other):
diff -r e165fea06e06 django/db/utils.py
--- a/django/db/utils.py	Thu Jan 14 17:43:46 2010 +0000
+++ b/django/db/utils.py	Tue Jan 19 23:17:54 2010 +0800
@@ -55,6 +55,7 @@
             conn = self.databases[alias]
         except KeyError:
             raise ConnectionDoesNotExist("The connection %s doesn't exist" % alias)
+
         conn.setdefault('ENGINE', 'django.db.backends.dummy')
         if conn['ENGINE'] == 'django.db.backends.' or not conn['ENGINE']:
             conn['ENGINE'] = 'django.db.backends.dummy'
@@ -65,6 +66,7 @@
         conn.setdefault('TIME_ZONE', settings.TIME_ZONE)
         for setting in ('NAME', 'USER', 'PASSWORD', 'HOST', 'PORT'):
             conn.setdefault(setting, '')
+        conn.setdefault('SOURCE', alias)
 
     def __getitem__(self, alias):
         if alias in self._connections:
diff -r e165fea06e06 tests/regressiontests/multiple_database/tests.py
--- a/tests/regressiontests/multiple_database/tests.py	Thu Jan 14 17:43:46 2010 +0000
+++ b/tests/regressiontests/multiple_database/tests.py	Tue Jan 19 23:17:54 2010 +0800
@@ -259,53 +259,53 @@
         self.assertEquals(list(Person.objects.using('other').filter(book__title='Dive into HTML5').values_list('name', flat=True)),
                           [u'Mark Pilgrim'])
 
-#    def test_m2m_cross_database_protection(self):
-#        "Operations that involve sharing M2M objects across databases raise an error"
-#        # Create a book and author on the default database
-#        pro = Book.objects.create(title="Pro Django",
-#                                  published=datetime.date(2008, 12, 16))
+    def test_m2m_cross_database_protection(self):
+        "Operations that involve sharing M2M objects across databases raise an error"
+        # Create a book and author on the default database
+        pro = Book.objects.create(title="Pro Django",
+                                  published=datetime.date(2008, 12, 16))
 
-#        marty = Person.objects.create(name="Marty Alchin")
+        marty = Person.objects.create(name="Marty Alchin")
 
-#        # Create a book and author on the other database
-#        dive = Book.objects.using('other').create(title="Dive into Python",
-#                                                  published=datetime.date(2009, 5, 4))
+        # Create a book and author on the other database
+        dive = Book.objects.using('other').create(title="Dive into Python",
+                                                  published=datetime.date(2009, 5, 4))
 
-#        mark = Person.objects.using('other').create(name="Mark Pilgrim")
-#        # Set a foreign key set with an object from a different database
-#        try:
-#            marty.book_set = [pro, dive]
-#            self.fail("Shouldn't be able to assign across databases")
-#        except ValueError:
-#            pass
+        mark = Person.objects.using('other').create(name="Mark Pilgrim")
+        # Set a foreign key set with an object from a different database
+        try:
+            marty.book_set = [pro, dive]
+            self.fail("Shouldn't be able to assign across databases")
+        except ValueError:
+            pass
 
-#        # Add to an m2m with an object from a different database
-#        try:
-#            marty.book_set.add(dive)
-#            self.fail("Shouldn't be able to assign across databases")
-#        except ValueError:
-#            pass
+        # Add to an m2m with an object from a different database
+        try:
+            marty.book_set.add(dive)
+            self.fail("Shouldn't be able to assign across databases")
+        except ValueError:
+            pass
 
-#        # Set a m2m with an object from a different database
-#        try:
-#            marty.book_set = [pro, dive]
-#            self.fail("Shouldn't be able to assign across databases")
-#        except ValueError:
-#            pass
+        # Set a m2m with an object from a different database
+        try:
+            marty.book_set = [pro, dive]
+            self.fail("Shouldn't be able to assign across databases")
+        except ValueError:
+            pass
 
-#        # Add to a reverse m2m with an object from a different database
-#        try:
-#            dive.authors.add(marty)
-#            self.fail("Shouldn't be able to assign across databases")
-#        except ValueError:
-#            pass
+        # Add to a reverse m2m with an object from a different database
+        try:
+            dive.authors.add(marty)
+            self.fail("Shouldn't be able to assign across databases")
+        except ValueError:
+            pass
 
-#        # Set a reverse m2m with an object from a different database
-#        try:
-#            dive.authors = [mark, marty]
-#            self.fail("Shouldn't be able to assign across databases")
-#        except ValueError:
-#            pass
+        # Set a reverse m2m with an object from a different database
+        try:
+            dive.authors = [mark, marty]
+            self.fail("Shouldn't be able to assign across databases")
+        except ValueError:
+            pass
 
     def test_foreign_key_separation(self):
         "FK fields are constrained to a single database"
@@ -401,88 +401,88 @@
         self.assertEquals(list(Person.objects.using('other').filter(edited__title='Dive into Python').values_list('name', flat=True)),
                           [])
 
-#    def test_foreign_key_cross_database_protection(self):
-#        "Operations that involve sharing FK objects across databases raise an error"
-#        # Create a book and author on the default database
-#        pro = Book.objects.create(title="Pro Django",
-#                                  published=datetime.date(2008, 12, 16))
+    def test_foreign_key_cross_database_protection(self):
+        "Operations that involve sharing FK objects across databases raise an error"
+        # Create a book and author on the default database
+        pro = Book.objects.create(title="Pro Django",
+                                  published=datetime.date(2008, 12, 16))
 
-#        marty = Person.objects.create(name="Marty Alchin")
+        marty = Person.objects.create(name="Marty Alchin")
 
-#        # Create a book and author on the other database
-#        dive = Book.objects.using('other').create(title="Dive into Python",
-#                                                  published=datetime.date(2009, 5, 4))
+        # Create a book and author on the other database
+        dive = Book.objects.using('other').create(title="Dive into Python",
+                                                  published=datetime.date(2009, 5, 4))
 
-#        mark = Person.objects.using('other').create(name="Mark Pilgrim")
+        mark = Person.objects.using('other').create(name="Mark Pilgrim")
 
-#        # Set a foreign key with an object from a different database
-#        try:
-#            dive.editor = marty
-#            self.fail("Shouldn't be able to assign across databases")
-#        except ValueError:
-#            pass
+        # Set a foreign key with an object from a different database
+        try:
+            dive.editor = marty
+            self.fail("Shouldn't be able to assign across databases")
+        except ValueError:
+            pass
 
-#        # Set a foreign key set with an object from a different database
-#        try:
-#            marty.edited = [pro, dive]
-#            self.fail("Shouldn't be able to assign across databases")
-#        except ValueError:
-#            pass
+        # Set a foreign key set with an object from a different database
+        try:
+            marty.edited = [pro, dive]
+            self.fail("Shouldn't be able to assign across databases")
+        except ValueError:
+            pass
 
-#        # Add to a foreign key set with an object from a different database
-#        try:
-#            marty.edited.add(dive)
-#            self.fail("Shouldn't be able to assign across databases")
-#        except ValueError:
-#            pass
+        # Add to a foreign key set with an object from a different database
+        try:
+            marty.edited.add(dive)
+            self.fail("Shouldn't be able to assign across databases")
+        except ValueError:
+            pass
 
-#        # BUT! if you assign a FK object when the base object hasn't
-#        # been saved yet, you implicitly assign the database for the
-#        # base object.
-#        chris = Person(name="Chris Mills")
-#        html5 = Book(title="Dive into HTML5", published=datetime.date(2010, 3, 15))
-#        # initially, no db assigned
-#        self.assertEquals(chris._state.db, None)
-#        self.assertEquals(html5._state.db, None)
+        # BUT! if you assign a FK object when the base object hasn't
+        # been saved yet, you implicitly assign the database for the
+        # base object.
+        chris = Person(name="Chris Mills")
+        html5 = Book(title="Dive into HTML5", published=datetime.date(2010, 3, 15))
+        # initially, no db assigned
+        self.assertEquals(chris._state.db, None)
+        self.assertEquals(html5._state.db, None)
 
-#        # old object comes from 'other', so the new object is set to use 'other'...
-#        dive.editor = chris
-#        html5.editor = mark
-#        # self.assertEquals(chris._state.db, 'other')
-#        self.assertEquals(html5._state.db, 'other')
-#        # ... but it isn't saved yet
-#        self.assertEquals(list(Person.objects.using('other').values_list('name',flat=True)),
-#                          [u'Mark Pilgrim'])
-#        self.assertEquals(list(Book.objects.using('other').values_list('title',flat=True)),
-#                           [u'Dive into Python'])
+        # old object comes from 'other', so the new object is set to use 'other'...
+        dive.editor = chris
+        html5.editor = mark
+        self.assertEquals(chris._state.db, 'other')
+        self.assertEquals(html5._state.db, 'other')
+        # ... but it isn't saved yet
+        self.assertEquals(list(Person.objects.using('other').values_list('name',flat=True)),
+                          [u'Mark Pilgrim'])
+        self.assertEquals(list(Book.objects.using('other').values_list('title',flat=True)),
+                           [u'Dive into Python'])
 
-#        # When saved (no using required), new objects goes to 'other'
-#        chris.save()
-#        html5.save()
-#        self.assertEquals(list(Person.objects.using('default').values_list('name',flat=True)),
-#                          [u'Marty Alchin'])
-#        self.assertEquals(list(Person.objects.using('other').values_list('name',flat=True)),
-#                          [u'Chris Mills', u'Mark Pilgrim'])
-#        self.assertEquals(list(Book.objects.using('default').values_list('title',flat=True)),
-#                          [u'Pro Django'])
-#        self.assertEquals(list(Book.objects.using('other').values_list('title',flat=True)),
-#                          [u'Dive into HTML5', u'Dive into Python'])
+        # When saved (no using required), new objects goes to 'other'
+        chris.save()
+        html5.save()
+        self.assertEquals(list(Person.objects.using('default').values_list('name',flat=True)),
+                          [u'Marty Alchin'])
+        self.assertEquals(list(Person.objects.using('other').values_list('name',flat=True)),
+                          [u'Chris Mills', u'Mark Pilgrim'])
+        self.assertEquals(list(Book.objects.using('default').values_list('title',flat=True)),
+                          [u'Pro Django'])
+        self.assertEquals(list(Book.objects.using('other').values_list('title',flat=True)),
+                          [u'Dive into HTML5', u'Dive into Python'])
 
-#        # This also works if you assign the FK in the constructor
-#        water = Book(title="Dive into Water", published=datetime.date(2001, 1, 1), editor=mark)
-#        self.assertEquals(water._state.db, 'other')
-#        # ... but it isn't saved yet
-#        self.assertEquals(list(Book.objects.using('default').values_list('title',flat=True)),
-#                          [u'Pro Django'])
-#        self.assertEquals(list(Book.objects.using('other').values_list('title',flat=True)),
-#                          [u'Dive into HTML5', u'Dive into Python'])
+        # This also works if you assign the FK in the constructor
+        water = Book(title="Dive into Water", published=datetime.date(2001, 1, 1), editor=mark)
+        self.assertEquals(water._state.db, 'other')
+        # ... but it isn't saved yet
+        self.assertEquals(list(Book.objects.using('default').values_list('title',flat=True)),
+                          [u'Pro Django'])
+        self.assertEquals(list(Book.objects.using('other').values_list('title',flat=True)),
+                          [u'Dive into HTML5', u'Dive into Python'])
 
-#        # When saved, the new book goes to 'other'
-#        water.save()
-#        self.assertEquals(list(Book.objects.using('default').values_list('title',flat=True)),
-#                          [u'Pro Django'])
-#        self.assertEquals(list(Book.objects.using('other').values_list('title',flat=True)),
-#                          [u'Dive into HTML5', u'Dive into Python', u'Dive into Water'])
+        # When saved, the new book goes to 'other'
+        water.save()
+        self.assertEquals(list(Book.objects.using('default').values_list('title',flat=True)),
+                          [u'Pro Django'])
+        self.assertEquals(list(Book.objects.using('other').values_list('title',flat=True)),
+                          [u'Dive into HTML5', u'Dive into Python', u'Dive into Water'])
 
     def test_generic_key_separation(self):
         "Generic fields are constrained to a single database"
@@ -555,56 +555,56 @@
         self.assertEquals(list(Review.objects.using('other').filter(object_id=dive.pk).values_list('source', flat=True)),
                           [u'Python Daily'])
 
-#    def test_generic_key_cross_database_protection(self):
-##        "Operations that involve sharing FK objects across databases raise an error"
-##        # Create a book and author on the default database
-##        pro = Book.objects.create(title="Pro Django",
-##                                  published=datetime.date(2008, 12, 16))
+    def test_generic_key_cross_database_protection(self):
+        "Operations that involve sharing generic key objects across databases raise an error"
+        # Create a book and author on the default database
+        pro = Book.objects.create(title="Pro Django",
+                                  published=datetime.date(2008, 12, 16))
 
-##        review1 = Review.objects.create(source="Python Monthly", content_object=pro)
+        review1 = Review.objects.create(source="Python Monthly", content_object=pro)
 
-##        # Create a book and author on the other database
-##        dive = Book.objects.using('other').create(title="Dive into Python",
-##                                                  published=datetime.date(2009, 5, 4))
+        # Create a book and author on the other database
+        dive = Book.objects.using('other').create(title="Dive into Python",
+                                                  published=datetime.date(2009, 5, 4))
 
-##        review2 = Review.objects.using('other').create(source="Python Weekly", content_object=dive)
+        review2 = Review.objects.using('other').create(source="Python Weekly", content_object=dive)
 
-##        # Set a foreign key with an object from a different database
-##        try:
-##            review1.content_object = dive
-##            self.fail("Shouldn't be able to assign across databases")
-##        except ValueError:
-##            pass
+        # Set a foreign key with an object from a different database
+        try:
+            review1.content_object = dive
+            self.fail("Shouldn't be able to assign across databases")
+        except ValueError:
+            pass
 
-#        # Add to a foreign key set with an object from a different database
-#        try:
-#            dive.reviews.add(review1)
-#            self.fail("Shouldn't be able to assign across databases")
-#        except ValueError:
-#            pass
+        # Add to a foreign key set with an object from a different database
+        try:
+            dive.reviews.add(review1)
+            self.fail("Shouldn't be able to assign across databases")
+        except ValueError:
+            pass
 
-#        # BUT! if you assign a FK object when the base object hasn't
-#        # been saved yet, you implicitly assign the database for the
-#        # base object.
-#        review3 = Review(source="Python Daily")
-#        # initially, no db assigned
-#        self.assertEquals(review3._state.db, None)
+        # BUT! if you assign a FK object when the base object hasn't
+        # been saved yet, you implicitly assign the database for the
+        # base object.
+        review3 = Review(source="Python Daily")
+        # initially, no db assigned
+        self.assertEquals(review3._state.db, None)
 
-#        # Dive comes from 'other', so review3 is set to use 'other'...
-#        review3.content_object = dive
-#        self.assertEquals(review3._state.db, 'other')
-#        # ... but it isn't saved yet
-#        self.assertEquals(list(Review.objects.using('default').filter(object_id=pro.pk).values_list('source', flat=True)),
-#                          [u'Python Monthly'])
-#        self.assertEquals(list(Review.objects.using('other').filter(object_id=dive.pk).values_list('source',flat=True)),
-#                          [u'Python Weekly'])
+        # Dive comes from 'other', so review3 is set to use 'other'...
+        review3.content_object = dive
+        self.assertEquals(review3._state.db, 'other')
+        # ... but it isn't saved yet
+        self.assertEquals(list(Review.objects.using('default').filter(object_id=pro.pk).values_list('source', flat=True)),
+                          [u'Python Monthly'])
+        self.assertEquals(list(Review.objects.using('other').filter(object_id=dive.pk).values_list('source',flat=True)),
+                          [u'Python Weekly'])
 
-#        # When saved, John goes to 'other'
-#        review3.save()
-#        self.assertEquals(list(Review.objects.using('default').filter(object_id=pro.pk).values_list('source', flat=True)),
-#                          [u'Python Monthly'])
-#        self.assertEquals(list(Review.objects.using('other').filter(object_id=dive.pk).values_list('source',flat=True)),
-#                          [u'Python Daily', u'Python Weekly'])
+        # When saved, John goes to 'other'
+        review3.save()
+        self.assertEquals(list(Review.objects.using('default').filter(object_id=pro.pk).values_list('source', flat=True)),
+                          [u'Python Monthly'])
+        self.assertEquals(list(Review.objects.using('other').filter(object_id=dive.pk).values_list('source',flat=True)),
+                          [u'Python Daily', u'Python Weekly'])
 
     def test_ordering(self):
         "get_next_by_XXX commands stick to a single database"
@@ -630,6 +630,302 @@
         val = Book.objects.raw('SELECT id FROM "multiple_database_book"').using('other')
         self.assertEqual(map(lambda o: o.pk, val), [dive.pk])
 
+class MasterSlaveTestCase(TestCase):
+    multi_db = True
+
+    def setUp(self):
+        # Make the 'other' database appear to be a slave of the 'default'
+        self.old_source = settings.DATABASES['other']['SOURCE']
+        settings.DATABASES['other']['SOURCE'] = 'default'
+
+    def tearDown(self):
+        # Restore the 'other' database as an independent database
+        settings.DATABASES['other']['SOURCE'] = self.old_source
+
+    def test_foreign_key_cross_database_protection(self):
+        "Foreign keys can cross databases if they two databases have a common source"
+        # Create a book and author on the default database
+        pro = Book.objects.create(title="Pro Django",
+                                  published=datetime.date(2008, 12, 16))
+
+        marty = Person.objects.create(name="Marty Alchin")
+
+        # Create a book and author on the other database
+        dive = Book.objects.using('other').create(title="Dive into Python",
+                                                  published=datetime.date(2009, 5, 4))
+
+        mark = Person.objects.using('other').create(name="Mark Pilgrim")
+
+        # Set a foreign key with an object from a different database
+        try:
+            dive.editor = marty
+        except ValueError:
+            self.fail("Assignment across master/slave databases with a common source should be ok")
+
+        # Database assignments of original objects haven't changed...
+        self.assertEquals(marty._state.db, 'default')
+        self.assertEquals(pro._state.db, 'default')
+        self.assertEquals(dive._state.db, 'other')
+        self.assertEquals(mark._state.db, 'other')
+
+        # ... but they will when the affected object is saved.
+        dive.save()
+        self.assertEquals(dive._state.db, 'default')
+
+        # ...and the source database now has a copy of any object saved
+        try:
+            Book.objects.using('default').get(title='Dive into Python').delete()
+        except Book.DoesNotExist:
+            self.fail('Source database should have a copy of saved object')
+
+        # This isn't a real master-slave database, so restore the original from other
+        dive = Book.objects.using('other').get(title='Dive into Python')
+        self.assertEquals(dive._state.db, 'other')
+
+        # Set a foreign key set with an object from a different database
+        try:
+            marty.edited = [pro, dive]
+        except ValueError:
+            self.fail("Assignment across master/slave databases with a common source should be ok")
+
+        # Assignment implies a save, so database assignments of original objects have changed...
+        self.assertEquals(marty._state.db, 'default')
+        self.assertEquals(pro._state.db, 'default')
+        self.assertEquals(dive._state.db, 'default')
+        self.assertEquals(mark._state.db, 'other')
+
+        # ...and the source database now has a copy of any object saved
+        try:
+            Book.objects.using('default').get(title='Dive into Python').delete()
+        except Book.DoesNotExist:
+            self.fail('Source database should have a copy of saved object')
+
+        # This isn't a real master-slave database, so restore the original from other
+        dive = Book.objects.using('other').get(title='Dive into Python')
+        self.assertEquals(dive._state.db, 'other')
+
+        # Add to a foreign key set with an object from a different database
+        try:
+            marty.edited.add(dive)
+        except ValueError:
+            self.fail("Assignment across master/slave databases with a common source should be ok")
+
+        # Add implies a save, so database assignments of original objects have changed...
+        self.assertEquals(marty._state.db, 'default')
+        self.assertEquals(pro._state.db, 'default')
+        self.assertEquals(dive._state.db, 'default')
+        self.assertEquals(mark._state.db, 'other')
+
+        # ...and the source database now has a copy of any object saved
+        try:
+            Book.objects.using('default').get(title='Dive into Python').delete()
+        except Book.DoesNotExist:
+            self.fail('Source database should have a copy of saved object')
+
+        # This isn't a real master-slave database, so restore the original from other
+        dive = Book.objects.using('other').get(title='Dive into Python')
+
+        # If you assign a FK object when the base object hasn't
+        # been saved yet, you implicitly assign the database for the
+        # base object.
+        chris = Person(name="Chris Mills")
+        html5 = Book(title="Dive into HTML5", published=datetime.date(2010, 3, 15))
+        # initially, no db assigned
+        self.assertEquals(chris._state.db, None)
+        self.assertEquals(html5._state.db, None)
+
+        # old object comes from 'other', so the new object is set to use the
+        # source of 'other'...
+        self.assertEquals(dive._state.db, 'other')
+        dive.editor = chris
+        html5.editor = mark
+
+        self.assertEquals(dive._state.db, 'other')
+        self.assertEquals(mark._state.db, 'other')
+        self.assertEquals(chris._state.db, 'default')
+        self.assertEquals(html5._state.db, 'default')
+
+        # This also works if you assign the FK in the constructor
+        water = Book(title="Dive into Water", published=datetime.date(2001, 1, 1), editor=mark)
+        self.assertEquals(water._state.db, 'default')
+
+    def test_m2m_cross_database_protection(self):
+        "M2M relations can cross databases if the database share a source"
+        # Create books and authors on the inverse to the usual database
+        pro = Book.objects.using('other').create(pk=1, title="Pro Django",
+                                                 published=datetime.date(2008, 12, 16))
+
+        marty = Person.objects.using('other').create(pk=1, name="Marty Alchin")
+
+        dive = Book.objects.using('default').create(pk=2, title="Dive into Python",
+                                                    published=datetime.date(2009, 5, 4))
+
+        mark = Person.objects.using('default').create(pk=2, name="Mark Pilgrim")
+
+        # Now save back onto the usual databse.
+        # This simulates master/slave - the objects exist on both database,
+        # but the _state.db is as it is for all other tests.
+        pro.save(using='default')
+        marty.save(using='default')
+        dive.save(using='other')
+        mark.save(using='other')
+
+        # Check that we have 2 of both types of object on both databases
+        self.assertEquals(Book.objects.using('default').count(), 2)
+        self.assertEquals(Book.objects.using('other').count(), 2)
+        self.assertEquals(Person.objects.using('default').count(), 2)
+        self.assertEquals(Person.objects.using('other').count(), 2)
+
+        # Set a m2m set with an object from a different database
+        try:
+            marty.book_set = [pro, dive]
+        except ValueError:
+            self.fail("Assignment across master/slave databases with a common source should be ok")
+
+        # Database assignments don't change
+        self.assertEquals(marty._state.db, 'default')
+        self.assertEquals(pro._state.db, 'default')
+        self.assertEquals(dive._state.db, 'other')
+        self.assertEquals(mark._state.db, 'other')
+
+        # All m2m relations should be saved on the default database
+        self.assertEquals(Book.authors.through.objects.using('default').count(), 2)
+        self.assertEquals(Book.authors.through.objects.using('other').count(), 0)
+
+        # Reset relations
+        Book.authors.through.objects.using('default').delete()
+
+        # Add to an m2m with an object from a different database
+        try:
+            marty.book_set.add(dive)
+        except ValueError:
+            self.fail("Assignment across master/slave databases with a common source should be ok")
+
+        # Database assignments don't change
+        self.assertEquals(marty._state.db, 'default')
+        self.assertEquals(pro._state.db, 'default')
+        self.assertEquals(dive._state.db, 'other')
+        self.assertEquals(mark._state.db, 'other')
+
+        # All m2m relations should be saved on the default database
+        self.assertEquals(Book.authors.through.objects.using('default').count(), 1)
+        self.assertEquals(Book.authors.through.objects.using('other').count(), 0)
+
+        # Reset relations
+        Book.authors.through.objects.using('default').delete()
+
+        # Set a reverse m2m with an object from a different database
+        try:
+            dive.authors = [mark, marty]
+        except ValueError:
+            self.fail("Assignment across master/slave databases with a common source should be ok")
+
+        # Database assignments don't change
+        self.assertEquals(marty._state.db, 'default')
+        self.assertEquals(pro._state.db, 'default')
+        self.assertEquals(dive._state.db, 'other')
+        self.assertEquals(mark._state.db, 'other')
+
+        # All m2m relations should be saved on the default database
+        self.assertEquals(Book.authors.through.objects.using('default').count(), 2)
+        self.assertEquals(Book.authors.through.objects.using('other').count(), 0)
+
+        # Reset relations
+        Book.authors.through.objects.using('default').delete()
+
+        self.assertEquals(Book.authors.through.objects.using('default').count(), 0)
+        self.assertEquals(Book.authors.through.objects.using('other').count(), 0)
+
+        # Add to a reverse m2m with an object from a different database
+        try:
+            dive.authors.add(marty)
+        except ValueError:
+            self.fail("Assignment across master/slave databases with a common source should be ok")
+
+        # Database assignments don't change
+        self.assertEquals(marty._state.db, 'default')
+        self.assertEquals(pro._state.db, 'default')
+        self.assertEquals(dive._state.db, 'other')
+        self.assertEquals(mark._state.db, 'other')
+
+        # All m2m relations should be saved on the default database
+        self.assertEquals(Book.authors.through.objects.using('default').count(), 1)
+        self.assertEquals(Book.authors.through.objects.using('other').count(), 0)
+
+    def test_generic_key_cross_database_protection(self):
+        "Generic Key operations can span databases if they share a source"
+        # Create a book and author on the default database
+        pro = Book.objects.create(title="Pro Django",
+                                  published=datetime.date(2008, 12, 16))
+
+        review1 = Review.objects.create(source="Python Monthly", content_object=pro)
+
+        # Create a book and author on the other database
+        dive = Book.objects.using('other').create(title="Dive into Python",
+                                                  published=datetime.date(2009, 5, 4))
+
+        review2 = Review.objects.using('other').create(source="Python Weekly", content_object=dive)
+
+        # Set a generic foreign key with an object from a different database
+        try:
+            review1.content_object = dive
+        except ValueError:
+            self.fail("Assignment across master/slave databases with a common source should be ok")
+
+        # Database assignments of original objects haven't changed...
+        self.assertEquals(pro._state.db, 'default')
+        self.assertEquals(review1._state.db, 'default')
+        self.assertEquals(dive._state.db, 'other')
+        self.assertEquals(review2._state.db, 'other')
+
+        # ... but they will when the affected object is saved.
+        dive.save()
+        self.assertEquals(review1._state.db, 'default')
+        self.assertEquals(dive._state.db, 'default')
+
+        # ...and the source database now has a copy of any object saved
+        try:
+            Book.objects.using('default').get(title='Dive into Python').delete()
+        except Book.DoesNotExist:
+            self.fail('Source database should have a copy of saved object')
+
+        # This isn't a real master-slave database, so restore the original from other
+        dive = Book.objects.using('other').get(title='Dive into Python')
+        self.assertEquals(dive._state.db, 'other')
+
+        # Add to a generic foreign key set with an object from a different database
+        try:
+            dive.reviews.add(review1)
+        except ValueError:
+            self.fail("Assignment across master/slave databases with a common source should be ok")
+
+        # Database assignments of original objects haven't changed...
+        self.assertEquals(pro._state.db, 'default')
+        self.assertEquals(review1._state.db, 'default')
+        self.assertEquals(dive._state.db, 'other')
+        self.assertEquals(review2._state.db, 'other')
+
+        # ... but they will when the affected object is saved.
+        dive.save()
+        self.assertEquals(dive._state.db, 'default')
+
+        # ...and the source database now has a copy of any object saved
+        try:
+            Book.objects.using('default').get(title='Dive into Python').delete()
+        except Book.DoesNotExist:
+            self.fail('Source database should have a copy of saved object')
+
+        # BUT! if you assign a FK object when the base object hasn't
+        # been saved yet, you implicitly assign the database for the
+        # base object.
+        review3 = Review(source="Python Daily")
+        # initially, no db assigned
+        self.assertEquals(review3._state.db, None)
+
+        # Dive comes from 'other', so review3 is set to use the source of 'other'...
+        review3.content_object = dive
+        self.assertEquals(review3._state.db, 'default')
+
 
 class UserProfileTestCase(TestCase):
     def setUp(self):
