#22666: (Generic)IPAddressField index never used on PostgreSQL, inconsistent
behavior
-------------------------------+--------------------
     Reporter:  intgr          |      Owner:  nobody
         Type:  Uncategorized  |     Status:  new
    Component:  Uncategorized  |    Version:  1.6
     Severity:  Normal         |   Keywords:
 Triage Stage:  Unreviewed     |  Has patch:  0
Easy pickings:  0              |      UI/UX:  0
-------------------------------+--------------------
 This isn't a problem for us currently, but something I noticed in the
 queries generated by Django, which I find to be an antifeature: fields
 that have GenericIPAddressField(db_index=True) are currently incapable of
 actually using the index in filters on PostgreSQL. The indexing does work
 on other databases because it's just a char/varchar field.

 For example, given model:
 {{{#!python
 class Ip(models.Model):
     ip = models.GenericIPAddressField(db_index=True)
 }}}
 The index is created as:
 {{{#!sql
 CREATE INDEX "asd_ip_ip" ON "asd_ip" ("ip");
 }}}

 And query filter clauses are generated using the `host()` database
 function. Since the index was created without the function, it cannot be
 used:
 {{{
 Ip.objects.filter(ip='1.2.3.4')
 # SELECT ... FROM "asd_ip" WHERE HOST("asd_ip"."ip") = '1.2.3.4'
 Ip.objects.filter(ip__gte='1.2.3.4')
 # SELECT ... FROM "asd_ip" WHERE HOST("asd_ip"."ip") >= '1.2.3.4'
 }}}

 Worse, since host() converts the IP address to text, the `__gte` filter
 stops making much sense, it will consider the IP address '255.0.0.0' to be
 less than '3.0.0.0'

 The index ''can'' be used for natural ordering, but the ordering will be
 inconsistent with the above `__gte` example and other greater/less than
 operators.
 {{{
 Ip.objects.order_by('ip')
 # SELECT ... FROM "asd_ip" ORDER BY "asd_ip"."ip" ASC
 }}}

 I understand that this was done to fix #708 -- the ability to use
 `__contains=` for IP addresses, but I think the cure is worse than the
 disease. In order to support an operation that doesn't make much sense for
 IP addresses, the change sacrifices the advantages that PostgreSQL's
 native `inet` type provides and makes ordering inconsistent with filter
 comparsisons.

 ----

 I think the "correct" way to address this is to revert that fix
 (a9b4efc82b23383038fed6da6ba97242aece27c1) and implement it the same way
 how `__contains` works for integers. The `::text` cast is universal and
 works with all data types in PostgreSQL:
 {{{
 Ip.objects.filter(pk__contains=123)
 # SELECT ... FROM "asd_ip" WHERE "asd_ip"."id"::text LIKE '%123%'
 }}}

 But this will break for users who are depending on the current `__gte` etc
 behavior in PostgreSQL, or expecting it to behave the same way in all
 databases.

 Another approach is to simply use `char`/`varchar` type (like other
 databases) instead of the PostgreSQL-specific `inet`, so it always uses
 text-ordering behavior and behaves the same in all databases without any
 hackery.

-- 
Ticket URL: <https://code.djangoproject.com/ticket/22666>
Django <https://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 unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/048.421f7442f6d00dc379384c4515617281%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to