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]: [, ] 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]: [, , ] }}} '''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