﻿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
6051	GenericRelation field lookups	litnimax	nobody	"== Problem descriptions ==
Currently [http://www.djangoproject.com/documentation/models/generic_relations/ GenericRelations] documentation does not say anything that it's possible.
I mean expression like 
{{{
Animal.objects.filter(tags__tag__exact='heavy')
}}}
 is not described there. But if we look in generic.py we can find there pretty much code that makes it possible. But apparently it's not ready yet. So I am creating here this ticket for discussion as I was told django developers list if not the right place to do it (my post is [http://groups.google.ru/group/django-developers/browse_thread/thread/60d72cc0d5d9d9d5/ here]).

So, at the moment I found the following issues.
 * Wrong field name when using intermediate tables,
{{{
for example, name__exact='bla-bla' worked,
but user__account__is_enabled=True did not work.
}}}
 Fixed in patch attached - [attachment:file:wrong_field_name.patch]
 * Not using content types table that makes possible for wrong results. Live example is below.

{{{
#!python
class Subscription(models.Model):
    """"""
    Universal model for all subscriptions.
    """"""
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField(db_index=True)
    account = models.ForeignKey(VoipAccount, verbose_name=_(""account""))
    currency = models.ForeignKey(Currency, verbose_name=_(""currency""))
    period = models.IntegerField(_(""period""), choices=PERIOD_CHOICES)
    setup = models.DecimalField(
        _(""setup fee""), max_digits=10, decimal_places=2)
    rate = models.DecimalField(
        _(""period rate""),  max_digits=10, decimal_places=2)
    create_date = models.DateTimeField(_(""created on""), db_index=True)
    paidtill_date = models.DateField(_(""paid till""), db_index=True)
    is_enabled = models.BooleanField(_(""is enabled""), db_index=True)
    content_object = generic.GenericForeignKey()
}}}

Now model that uses Subscription:
{{{
#!python
class LocalNumber(models.Model):
    number = models.CharField(_('number'), max_length=10, unique=True)
    subscription = generic.GenericRelation(Subscription)
}}}

These models make it possible for users to ""subscribe"" to numbers. It generates the following code:
{{{
#!python
In [48]: LocalNumber.objects.filter(subscription__is_enabled=True)
Out[48]: [<LocalNumber: 1000>, <LocalNumber: 1020>]

Out[49]: 
(['`provider_localnumber`.`id`',
  '`provider_localnumber`.`pool_id`',
  '`provider_localnumber`.`sub_pool_id`',
  '`provider_localnumber`.`number`'],
 ' FROM `provider_localnumber` LEFT OUTER JOIN `billing_subscription` AS `m2m_provider_localnumber__subscription` ON `provider_localnumber`.`id` = `m2m_provider_localnumber__subscription`.`object_id` INNER JOIN `billing_subscription` AS `provider_localnumber__subscription` ON `m2m_provider_localnumber__subscription`.`id` = `provider_localnumber__subscription`.`id` WHERE (`provider_localnumber__subscription`.`is_enabled` = %s)',
 [True])

}}}

I do not see any relations with content types. Imagine that some other model has same object_id? Our initial situation is correct:
{{{
mysql> select * from billing_subscription;                                                                                                                               +----+-----------------+-----------+------------+-------------+--------+-------+------+---------------------+---------------+------------+                               | id | content_type_id | object_id | account_id | currency_id | period | setup | rate | create_date         | paidtill_date | is_enabled |                               +----+-----------------+-----------+------------+-------------+--------+-------+------+---------------------+---------------+------------+
| 54 |             174 |     46317 |      20865 |           1 |      1 |  0.00 | 0.00 | 2007-11-28 23:52:53 | 2008-11-27    |          1 |
| 53 |             174 |     46337 |      20865 |           1 |      1 |  0.00 | 0.00 | 2007-11-28 21:09:39 | 2008-11-27    |          1 |
+----+-----------------+-----------+------------+-------------+--------+-------+------+---------------------+---------------+------------+
}}}
Now let ""subscribe"" some other model:
{{{
mysql> insert into billing_subscription (content_type_id, object_id, account_id, is_enabled) values (12, 46337, 20865, 1);
       
mysql> select * from billing_subscription;
+----+-----------------+-----------+------------+-------------+--------+-------+------+---------------------+---------------+------------+
| id | content_type_id | object_id | account_id | currency_id | period | setup | rate | create_date         | paidtill_date | is_enabled |
+----+-----------------+-----------+------------+-------------+--------+-------+------+---------------------+---------------+------------+
| 54 |             174 |     46317 |      20865 |           1 |      1 |  0.00 | 0.00 | 2007-11-28 23:52:53 | 2008-11-27    |          1 |
| 53 |             174 |     46337 |      20865 |           1 |      1 |  0.00 | 0.00 | 2007-11-28 21:09:39 | 2008-11-27    |          1 |
| 55 |              12 |     46337 |      20865 |           0 |      0 |  0.00 | 0.00 | 0000-00-00 00:00:00 | 0000-00-00    |          1 |
+----+-----------------+-----------+------------+-------------+--------+-------+------+---------------------+---------------+------------+
}}}
As you can see subscription.id=55 has content_type_id=12 and content_object is not !LocalNumber. Let proove it:
{{{
#!python
In [61]: print Subscription.objects.get(pk=53).content_object
1020
In [62]: print Subscription.objects.get(pk=54).content_object
1000
In [63]: print Subscription.objects.get(pk=55).content_object
None
}}}
As you can see there are only 2 subscriptions to numbers (We got None for 3-rd line because there is no such object_id for model id 12). But let see again:
{{{
#!python
In [64]: LocalNumber.objects.filter(subscription__is_enabled=True)
Out[64]: [<LocalNumber: 1000>, <LocalNumber: 1020>, <LocalNumber: 1020>]
}}}
'''What happened!?''' Why do we have 3 numbers instead of 2? This is because current implementation does not use content types table. 

To be continued..."		closed	Database layer (models, ORM)	dev		fixed	generic	drackett@…	Accepted	1	0	1	1	0	0
