1
0
mirror of https://github.com/django/django.git synced 2025-07-04 17:59:13 +00:00

[soc2009/multidb] Fixed a problem with m2m descriptors not sticking to the right database. Patch from Russell Keith-Magee.

git-svn-id: http://code.djangoproject.com/svn/django/branches/soc2009/multidb@11873 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Alex Gaynor 2009-12-16 07:01:56 +00:00
parent 05b4d2f67b
commit fc36471d1b
3 changed files with 32 additions and 5 deletions

3
TODO
View File

@ -5,6 +5,9 @@ Required for v1.2
~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~
* Modify the admin interface to support multiple databases (doh). * Modify the admin interface to support multiple databases (doh).
- Document how it is done
- Modify m2m widgets to stick to the same database as parent
- Modify inlines to stick to same database as parent
Optional for v1.2 Optional for v1.2
~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~

View File

@ -439,7 +439,7 @@ def create_many_related_manager(superclass, rel=False):
raise ValueError("%r instance needs to have a primary key value before a many-to-many relationship can be used." % instance.__class__.__name__) raise ValueError("%r instance needs to have a primary key value before a many-to-many relationship can be used." % instance.__class__.__name__)
def get_query_set(self): def get_query_set(self):
return superclass.get_query_set(self)._next_is_sticky().filter(**(self.core_filters)) return superclass.get_query_set(self).using(self.instance._state.db)._next_is_sticky().filter(**(self.core_filters))
# If the ManyToMany relation has an intermediary model, # If the ManyToMany relation has an intermediary model,
# the add and remove methods do not exist. # the add and remove methods do not exist.
@ -709,7 +709,7 @@ class ManyToManyRel(object):
class ForeignKey(RelatedField, Field): class ForeignKey(RelatedField, Field):
"""Foreign Key (type determined by related field)""" """Foreign Key (type determined by related field)"""
empty_strings_allowed = False empty_strings_allowed = False
def __init__(self, to, to_field=None, rel_class=ManyToOneRel, **kwargs): def __init__(self, to, to_field=None, rel_class=ManyToOneRel, **kwargs):
try: try:
@ -809,7 +809,7 @@ class ForeignKey(RelatedField, Field):
class OneToOneField(ForeignKey): class OneToOneField(ForeignKey):
"""One-to-one relationship """One-to-one relationship
A OneToOneField is essentially the same as a ForeignKey, with the exception A OneToOneField is essentially the same as a ForeignKey, with the exception
that always carries a "unique" constraint with it and the reverse relation that always carries a "unique" constraint with it and the reverse relation
always returns the object pointed to (since there will only ever be one), always returns the object pointed to (since there will only ever be one),
@ -869,7 +869,7 @@ def create_many_to_many_intermediary_model(field, klass):
class ManyToManyField(RelatedField, Field): class ManyToManyField(RelatedField, Field):
"""Many-to-many relationship""" """Many-to-many relationship"""
def __init__(self, to, **kwargs): def __init__(self, to, **kwargs):
try: try:
assert not to._meta.abstract, "%s cannot define a relation with abstract class %s" % (self.__class__.__name__, to._meta.object_name) assert not to._meta.abstract, "%s cannot define a relation with abstract class %s" % (self.__class__.__name__, to._meta.object_name)
@ -1032,7 +1032,10 @@ class ManyToManyField(RelatedField, Field):
setattr(instance, self.attname, data) setattr(instance, self.attname, data)
def formfield(self, **kwargs): def formfield(self, **kwargs):
defaults = {'form_class': forms.ModelMultipleChoiceField, 'queryset': self.rel.to._default_manager.complex_filter(self.rel.limit_choices_to)} defaults = {
'form_class': forms.ModelMultipleChoiceField,
'queryset': self.rel.to._default_manager.complex_filter(self.rel.limit_choices_to)
}
defaults.update(kwargs) defaults.update(kwargs)
# If initial is passed in, it's a list of related objects, but the # If initial is passed in, it's a list of related objects, but the
# MultipleChoiceField takes a list of IDs. # MultipleChoiceField takes a list of IDs.

View File

@ -160,6 +160,17 @@ class QueryTestCase(TestCase):
self.assertEquals(list(Book.objects.using('other').filter(authors__name='Mark Pilgrim').values_list('title', flat=True)), self.assertEquals(list(Book.objects.using('other').filter(authors__name='Mark Pilgrim').values_list('title', flat=True)),
[u'Dive into Python']) [u'Dive into Python'])
# Reget the objects to clear caches
dive = Book.objects.using('other').get(title="Dive into Python")
mark = Author.objects.using('other').get(name="Mark Pilgrim")
# Retrive related object by descriptor. Related objects should be database-baound
self.assertEquals(list(dive.authors.all().values_list('name', flat=True)),
[u'Mark Pilgrim'])
self.assertEquals(list(mark.book_set.all().values_list('title', flat=True)),
[u'Dive into Python'])
def test_m2m_forward_operations(self): def test_m2m_forward_operations(self):
"M2M forward manipulations are all constrained to a single DB" "M2M forward manipulations are all constrained to a single DB"
# Create a book and author on the other database # Create a book and author on the other database
@ -286,6 +297,16 @@ class QueryTestCase(TestCase):
self.assertEquals(list(Book.objects.using('other').filter(favourite_of__name='Mark Pilgrim').values_list('title', flat=True)), self.assertEquals(list(Book.objects.using('other').filter(favourite_of__name='Mark Pilgrim').values_list('title', flat=True)),
[u'Dive into Python']) [u'Dive into Python'])
# Reget the objects to clear caches
dive = Book.objects.using('other').get(title="Dive into Python")
mark = Author.objects.using('other').get(name="Mark Pilgrim")
# Retrive related object by descriptor. Related objects should be database-baound
self.assertEquals(list(dive.favourite_of.all().values_list('name', flat=True)),
[u'Mark Pilgrim'])
self.assertEquals(mark.favourite_book.title, u'Dive into Python')
def test_foreign_key_reverse_operations(self): def test_foreign_key_reverse_operations(self):
"FK reverse manipulations are all constrained to a single DB" "FK reverse manipulations are all constrained to a single DB"
dive = Book.objects.using('other').create(title="Dive into Python", dive = Book.objects.using('other').create(title="Dive into Python",