1
0
mirror of https://github.com/django/django.git synced 2025-07-05 18:29:11 +00:00

[soc2009/multidb] Remove cross database protection. This will be readded in a way that is more ammenable to master-slave and other mirroring schemes.

git-svn-id: http://code.djangoproject.com/svn/django/branches/soc2009/multidb@11927 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Alex Gaynor 2009-12-21 03:39:00 +00:00
parent 4424a8d3d8
commit e4f8015112
2 changed files with 162 additions and 165 deletions

View File

@ -1,7 +1,8 @@
from django.db import connection, transaction, DEFAULT_DB_ALIAS from django.db import connection, transaction, DEFAULT_DB_ALIAS
from django.db.backends import util from django.db.backends import util
from django.db.models import signals, get_model from django.db.models import signals, get_model
from django.db.models.fields import AutoField, Field, IntegerField, PositiveIntegerField, PositiveSmallIntegerField, FieldDoesNotExist from django.db.models.fields import (AutoField, Field, IntegerField,
PositiveIntegerField, PositiveSmallIntegerField, FieldDoesNotExist)
from django.db.models.related import RelatedObject from django.db.models.related import RelatedObject
from django.db.models.query import QuerySet from django.db.models.query import QuerySet
from django.db.models.query_utils import QueryWrapper from django.db.models.query_utils import QueryWrapper
@ -11,10 +12,6 @@ from django.utils.functional import curry
from django.core import exceptions from django.core import exceptions
from django import forms from django import forms
try:
set
except NameError:
from sets import Set as set # Python 2.3 fallback
RECURSIVE_RELATIONSHIP_CONSTANT = 'self' RECURSIVE_RELATIONSHIP_CONSTANT = 'self'
@ -284,11 +281,11 @@ class ReverseSingleRelatedObjectDescriptor(object):
elif value is not None and value._state.db != instance._state.db: elif value is not None and value._state.db != instance._state.db:
if instance._state.db is None: if instance._state.db is None:
instance._state.db = value._state.db instance._state.db = value._state.db
elif value._state.db is None: else:#elif value._state.db is None:
value._state.db = instance._state.db value._state.db = instance._state.db
elif value._state.db is not None and instance._state.db is not None: # 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"' % # raise ValueError('Cannot assign "%r": instance is on database "%s", value is is on database "%s"' %
(value, instance._state.db, value._state.db)) # (value, instance._state.db, value._state.db))
# If we're setting the value of a OneToOneField to None, we need to clear # 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 # out the cache on any old related object. Otherwise, deleting the
@ -503,9 +500,9 @@ def create_many_related_manager(superclass, rel=False):
new_ids = set() new_ids = set()
for obj in objs: for obj in objs:
if isinstance(obj, self.model): if isinstance(obj, self.model):
if obj._state.db != self.instance._state.db: # if obj._state.db != self.instance._state.db:
raise ValueError('Cannot add "%r": instance is on database "%s", value is is on database "%s"' % # raise ValueError('Cannot add "%r": instance is on database "%s", value is is on database "%s"' %
(obj, self.instance._state.db, obj._state.db)) # (obj, self.instance._state.db, obj._state.db))
new_ids.add(obj.pk) new_ids.add(obj.pk)
elif isinstance(obj, Model): elif isinstance(obj, Model):
raise TypeError, "'%s' instance expected" % self.model._meta.object_name raise TypeError, "'%s' instance expected" % self.model._meta.object_name

View File

@ -259,53 +259,53 @@ class QueryTestCase(TestCase):
self.assertEquals(list(Person.objects.using('other').filter(book__title='Dive into HTML5').values_list('name', flat=True)), self.assertEquals(list(Person.objects.using('other').filter(book__title='Dive into HTML5').values_list('name', flat=True)),
[u'Mark Pilgrim']) [u'Mark Pilgrim'])
def test_m2m_cross_database_protection(self): # def test_m2m_cross_database_protection(self):
"Operations that involve sharing M2M objects across databases raise an error" # "Operations that involve sharing M2M objects across databases raise an error"
# Create a book and author on the default database # # Create a book and author on the default database
pro = Book.objects.create(title="Pro Django", # pro = Book.objects.create(title="Pro Django",
published=datetime.date(2008, 12, 16)) # 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 # # Create a book and author on the other database
dive = Book.objects.using('other').create(title="Dive into Python", # dive = Book.objects.using('other').create(title="Dive into Python",
published=datetime.date(2009, 5, 4)) # 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 set with an object from a different database # # Set a foreign key set with an object from a different database
try: # try:
marty.book_set = [pro, dive] # marty.book_set = [pro, dive]
self.fail("Shouldn't be able to assign across databases") # self.fail("Shouldn't be able to assign across databases")
except ValueError: # except ValueError:
pass # pass
# Add to an m2m with an object from a different database # # Add to an m2m with an object from a different database
try: # try:
marty.book_set.add(dive) # marty.book_set.add(dive)
self.fail("Shouldn't be able to assign across databases") # self.fail("Shouldn't be able to assign across databases")
except ValueError: # except ValueError:
pass # pass
# Set a m2m with an object from a different database # # Set a m2m with an object from a different database
try: # try:
marty.book_set = [pro, dive] # marty.book_set = [pro, dive]
self.fail("Shouldn't be able to assign across databases") # self.fail("Shouldn't be able to assign across databases")
except ValueError: # except ValueError:
pass # pass
# Add to a reverse m2m with an object from a different database # # Add to a reverse m2m with an object from a different database
try: # try:
dive.authors.add(marty) # dive.authors.add(marty)
self.fail("Shouldn't be able to assign across databases") # self.fail("Shouldn't be able to assign across databases")
except ValueError: # except ValueError:
pass # pass
# Set a reverse m2m with an object from a different database # # Set a reverse m2m with an object from a different database
try: # try:
dive.authors = [mark, marty] # dive.authors = [mark, marty]
self.fail("Shouldn't be able to assign across databases") # self.fail("Shouldn't be able to assign across databases")
except ValueError: # except ValueError:
pass # pass
def test_foreign_key_separation(self): def test_foreign_key_separation(self):
"FK fields are constrained to a single database" "FK fields are constrained to a single database"
@ -401,88 +401,88 @@ class QueryTestCase(TestCase):
self.assertEquals(list(Person.objects.using('other').filter(edited__title='Dive into Python').values_list('name', flat=True)), 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): # def test_foreign_key_cross_database_protection(self):
"Operations that involve sharing FK objects across databases raise an error" # "Operations that involve sharing FK objects across databases raise an error"
# Create a book and author on the default database # # Create a book and author on the default database
pro = Book.objects.create(title="Pro Django", # pro = Book.objects.create(title="Pro Django",
published=datetime.date(2008, 12, 16)) # 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 # # Create a book and author on the other database
dive = Book.objects.using('other').create(title="Dive into Python", # dive = Book.objects.using('other').create(title="Dive into Python",
published=datetime.date(2009, 5, 4)) # 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 # # Set a foreign key with an object from a different database
try: # try:
dive.editor = marty # dive.editor = marty
self.fail("Shouldn't be able to assign across databases") # self.fail("Shouldn't be able to assign across databases")
except ValueError: # except ValueError:
pass # pass
# Set a foreign key set with an object from a different database # # Set a foreign key set with an object from a different database
try: # try:
marty.edited = [pro, dive] # marty.edited = [pro, dive]
self.fail("Shouldn't be able to assign across databases") # self.fail("Shouldn't be able to assign across databases")
except ValueError: # except ValueError:
pass # pass
# Add to a foreign key set with an object from a different database # # Add to a foreign key set with an object from a different database
try: # try:
marty.edited.add(dive) # marty.edited.add(dive)
self.fail("Shouldn't be able to assign across databases") # self.fail("Shouldn't be able to assign across databases")
except ValueError: # except ValueError:
pass # pass
# BUT! if you assign a FK object when the base object hasn't # # BUT! if you assign a FK object when the base object hasn't
# been saved yet, you implicitly assign the database for the # # been saved yet, you implicitly assign the database for the
# base object. # # base object.
chris = Person(name="Chris Mills") # chris = Person(name="Chris Mills")
html5 = Book(title="Dive into HTML5", published=datetime.date(2010, 3, 15)) # html5 = Book(title="Dive into HTML5", published=datetime.date(2010, 3, 15))
# initially, no db assigned # # initially, no db assigned
self.assertEquals(chris._state.db, None) # self.assertEquals(chris._state.db, None)
self.assertEquals(html5._state.db, None) # self.assertEquals(html5._state.db, None)
# old object comes from 'other', so the new object is set to use 'other'... # # old object comes from 'other', so the new object is set to use 'other'...
dive.editor = chris # dive.editor = chris
html5.editor = mark # html5.editor = mark
# self.assertEquals(chris._state.db, 'other') # # self.assertEquals(chris._state.db, 'other')
self.assertEquals(html5._state.db, 'other') # self.assertEquals(html5._state.db, 'other')
# ... but it isn't saved yet # # ... but it isn't saved yet
self.assertEquals(list(Person.objects.using('other').values_list('name',flat=True)), # self.assertEquals(list(Person.objects.using('other').values_list('name',flat=True)),
[u'Mark Pilgrim']) # [u'Mark Pilgrim'])
self.assertEquals(list(Book.objects.using('other').values_list('title',flat=True)), # self.assertEquals(list(Book.objects.using('other').values_list('title',flat=True)),
[u'Dive into Python']) # [u'Dive into Python'])
# When saved (no using required), new objects goes to 'other' # # When saved (no using required), new objects goes to 'other'
chris.save() # chris.save()
html5.save() # html5.save()
self.assertEquals(list(Person.objects.using('default').values_list('name',flat=True)), # self.assertEquals(list(Person.objects.using('default').values_list('name',flat=True)),
[u'Marty Alchin']) # [u'Marty Alchin'])
self.assertEquals(list(Person.objects.using('other').values_list('name',flat=True)), # self.assertEquals(list(Person.objects.using('other').values_list('name',flat=True)),
[u'Chris Mills', u'Mark Pilgrim']) # [u'Chris Mills', u'Mark Pilgrim'])
self.assertEquals(list(Book.objects.using('default').values_list('title',flat=True)), # self.assertEquals(list(Book.objects.using('default').values_list('title',flat=True)),
[u'Pro Django']) # [u'Pro Django'])
self.assertEquals(list(Book.objects.using('other').values_list('title',flat=True)), # self.assertEquals(list(Book.objects.using('other').values_list('title',flat=True)),
[u'Dive into HTML5', u'Dive into Python']) # [u'Dive into HTML5', u'Dive into Python'])
# This also works if you assign the FK in the constructor # # 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) # water = Book(title="Dive into Water", published=datetime.date(2001, 1, 1), editor=mark)
self.assertEquals(water._state.db, 'other') # self.assertEquals(water._state.db, 'other')
# ... but it isn't saved yet # # ... but it isn't saved yet
self.assertEquals(list(Book.objects.using('default').values_list('title',flat=True)), # self.assertEquals(list(Book.objects.using('default').values_list('title',flat=True)),
[u'Pro Django']) # [u'Pro Django'])
self.assertEquals(list(Book.objects.using('other').values_list('title',flat=True)), # self.assertEquals(list(Book.objects.using('other').values_list('title',flat=True)),
[u'Dive into HTML5', u'Dive into Python']) # [u'Dive into HTML5', u'Dive into Python'])
# When saved, the new book goes to 'other' # # When saved, the new book goes to 'other'
water.save() # water.save()
self.assertEquals(list(Book.objects.using('default').values_list('title',flat=True)), # self.assertEquals(list(Book.objects.using('default').values_list('title',flat=True)),
[u'Pro Django']) # [u'Pro Django'])
self.assertEquals(list(Book.objects.using('other').values_list('title',flat=True)), # self.assertEquals(list(Book.objects.using('other').values_list('title',flat=True)),
[u'Dive into HTML5', u'Dive into Python', u'Dive into Water']) # [u'Dive into HTML5', u'Dive into Python', u'Dive into Water'])
def test_generic_key_separation(self): def test_generic_key_separation(self):
"Generic fields are constrained to a single database" "Generic fields are constrained to a single database"
@ -555,56 +555,56 @@ class QueryTestCase(TestCase):
self.assertEquals(list(Review.objects.using('other').filter(object_id=dive.pk).values_list('source', flat=True)), self.assertEquals(list(Review.objects.using('other').filter(object_id=dive.pk).values_list('source', flat=True)),
[u'Python Daily']) [u'Python Daily'])
def test_generic_key_cross_database_protection(self): # def test_generic_key_cross_database_protection(self):
"Operations that involve sharing FK objects across databases raise an error" ## "Operations that involve sharing FK objects across databases raise an error"
# Create a book and author on the default database ## # Create a book and author on the default database
pro = Book.objects.create(title="Pro Django", ## pro = Book.objects.create(title="Pro Django",
published=datetime.date(2008, 12, 16)) ## 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 ## # Create a book and author on the other database
dive = Book.objects.using('other').create(title="Dive into Python", ## dive = Book.objects.using('other').create(title="Dive into Python",
published=datetime.date(2009, 5, 4)) ## 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 ## # Set a foreign key with an object from a different database
try: ## try:
review1.content_object = dive ## review1.content_object = dive
self.fail("Shouldn't be able to assign across databases") ## self.fail("Shouldn't be able to assign across databases")
except ValueError: ## except ValueError:
pass ## pass
# Add to a foreign key set with an object from a different database # # Add to a foreign key set with an object from a different database
try: # try:
dive.reviews.add(review1) # dive.reviews.add(review1)
self.fail("Shouldn't be able to assign across databases") # self.fail("Shouldn't be able to assign across databases")
except ValueError: # except ValueError:
pass # pass
# BUT! if you assign a FK object when the base object hasn't # # BUT! if you assign a FK object when the base object hasn't
# been saved yet, you implicitly assign the database for the # # been saved yet, you implicitly assign the database for the
# base object. # # base object.
review3 = Review(source="Python Daily") # review3 = Review(source="Python Daily")
# initially, no db assigned # # initially, no db assigned
self.assertEquals(review3._state.db, None) # self.assertEquals(review3._state.db, None)
# Dive comes from 'other', so review3 is set to use 'other'... # # Dive comes from 'other', so review3 is set to use 'other'...
review3.content_object = dive # review3.content_object = dive
self.assertEquals(review3._state.db, 'other') # self.assertEquals(review3._state.db, 'other')
# ... but it isn't saved yet # # ... but it isn't saved yet
self.assertEquals(list(Review.objects.using('default').filter(object_id=pro.pk).values_list('source', flat=True)), # self.assertEquals(list(Review.objects.using('default').filter(object_id=pro.pk).values_list('source', flat=True)),
[u'Python Monthly']) # [u'Python Monthly'])
self.assertEquals(list(Review.objects.using('other').filter(object_id=dive.pk).values_list('source',flat=True)), # self.assertEquals(list(Review.objects.using('other').filter(object_id=dive.pk).values_list('source',flat=True)),
[u'Python Weekly']) # [u'Python Weekly'])
# When saved, John goes to 'other' # # When saved, John goes to 'other'
review3.save() # review3.save()
self.assertEquals(list(Review.objects.using('default').filter(object_id=pro.pk).values_list('source', flat=True)), # self.assertEquals(list(Review.objects.using('default').filter(object_id=pro.pk).values_list('source', flat=True)),
[u'Python Monthly']) # [u'Python Monthly'])
self.assertEquals(list(Review.objects.using('other').filter(object_id=dive.pk).values_list('source',flat=True)), # self.assertEquals(list(Review.objects.using('other').filter(object_id=dive.pk).values_list('source',flat=True)),
[u'Python Daily', u'Python Weekly']) # [u'Python Daily', u'Python Weekly'])
def test_ordering(self): def test_ordering(self):
"get_next_by_XXX commands stick to a single database" "get_next_by_XXX commands stick to a single database"