#6051: GenericRelation field lookups
-----------------------+----------------------------------------------------
Reporter: litnimax | Owner: nobody
Status: new | Component: Uncategorized
Version: SVN | Keywords: generic
Stage: Unreviewed | Has_patch: 1
-----------------------+----------------------------------------------------
== 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...
--
Ticket URL: <http://code.djangoproject.com/ticket/6051>
Django Code <http://code.djangoproject.com/>
The web framework for perfectionists with deadlines
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"Django updates" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at
http://groups.google.com/group/django-updates?hl=en
-~----------~----~----~----~------~----~------~--~---