﻿id	summary	reporter	owner	description	type	status	component	version	severity	resolution	keywords	cc	stage	has_patch	needs_docs	needs_tests	needs_better_patch	easy	ui_ux
15610	Generic Foreign Keys break when used with multi-db.	legutierr	nobody	"Specifically, retrieving and saving objects that use the !GenericForeignKey descriptor fails when the !ContentType table is stored in a different database than the table of the instance being retrieved or saved.

There can only be one valid and consistent content-type table in a system.  In a two-db system, the content type table will be in either db A or db B.  Therefore, a portion of the system's tables will be registered in a content-type table that is stored in a different database.

This is all OK when retrieving objects based on a !GenericForeignKey reference, because a user in such a situation will typically rely on the underlying routers to determine which database to use in retrieving content-type records. 

However, this method in [http://code.djangoproject.com/browser/django/trunk/django/contrib/contenttypes/generic.py#L52 django/trunk/django/contrib/contenttypes/generic.py] does not use routers in determining what database to use to fetch the content-type, but instead uses the source database of the orm object the content-type of which is being queried:

{{{
52	    def get_content_type(self, obj=None, id=None, using=None):
53	        # Convenience function using get_model avoids a circular import when
54	        # using this model
55	        ContentType = get_model(""contenttypes"", ""contenttype"")
56	        if obj:
57	             return ContentType.objects.db_manager(obj._state.db).get_for_model(obj)
58	        elif id:
59	             return ContentType.objects.db_manager(using).get_for_id(id)
60	        else:
61	            # This should never happen. I love comments like this, don't you?
62	            raise Exception(""Impossible arguments to GFK.get_content_type!"")
}}}

The above method is what is used at object-creation time to transform a generic object in the `__init__` kwargs of a new orm object into a content-type/object-id pair for purposes of saving.  The use of this method results in either: (a) an error being generated when the specified table is not to be found in the designated database; or (b) incorrect information being saved when a parallel--but incorrect (according to the router rules)--content type table from the other database is used (i.e. database corruption).

A simple fix would be to not assume that the content-types table is in the same database as the object with the !GenericForeignKey field.  I don't have a patch right now, but it may be as simple as replacing line 57:

{{{
57	             return ContentType.objects.db_manager(obj._state.db).get_for_model(obj)
}}}

with:

{{{
57	             return ContentType.objects.db_manager(using).get_for_model(obj)
}}}

A similar error seems to exist in the following block of code as well, however:

{{{
220	        manager = RelatedManager(
221	            model = rel_model,
222	            instance = instance,
223	            symmetrical = (self.field.rel.symmetrical and instance.__class__ == rel_model),
224	            join_table = qn(self.field.m2m_db_table()),
225	            source_col_name = qn(self.field.m2m_column_name()),
226	            target_col_name = qn(self.field.m2m_reverse_name()),
227	            content_type = ContentType.objects.db_manager(instance._state.db).get_for_model(instance),
228	            content_type_field_name = self.field.content_type_field_name,
229	            object_id_field_name = self.field.object_id_field_name
230	        )
}}}

Requiring that line 227 be replaced, perhaps:

{{{
227	            content_type = ContentType.objects.get_for_model(instance),
}}}

The problem here is that no `using` argument is specified for the `__get__` method, nor can a `using` argument be specified there, making the usage in that function inconsistent with the rest of the file, should this fix be put in place."	Bug	new	contrib.contenttypes	dev	Normal			django@… albrecht.andi@… 4glitch@… django@… bcail	Accepted	1	0	1	0	0	0
