#31872: Postgres DecimalRangeField ignores bounds
--------------------------------------------+------------------------
               Reporter:  Jack Delany       |          Owner:  (none)
                   Type:  Uncategorized     |         Status:  new
              Component:  contrib.postgres  |        Version:  3.1
               Severity:  Normal            |       Keywords:
           Triage Stage:  Unreviewed        |      Has patch:  0
    Needs documentation:  0                 |    Needs tests:  0
Patch needs improvement:  0                 |  Easy pickings:  0
                  UI/UX:  0                 |
--------------------------------------------+------------------------
 Found in 2.2, still in master.

 I believe there is an issue in the internal conversion/prep routine for
 Range types.
 {{{
 from django.contrib.postgres.fields.ranges import DecimalRangeField

 class OneModel(models.Model):
     val = DecimalRangeField()
 }}}

 Given a simple object created from a tuple:
 {{{
 x = OneModel(val=(1.0, 2.0, "[]"))
 x.save()
 }}}
 This emits the following SQL with an incorrect bounds:
 {{{
 INSERT INTO "app_onemodel" ("val") VALUES ('[1.0,2.0)')  ...
 }}}

 Alternately:
 {{{
 from psycopg2.extras import NumericRange
 x = OneModel(val=NumericRange(1.0, 2.0, "[]"))
 x.save()
 }}}
 This one does what I expect and emits the following SQL and preserves the
 bounds:
 {{{
 INSERT INTO "app_onemodel" ("val") VALUES ('[1.0,2.0]')  ...
 }}}
 I tracked it down to:
 {{{
 django/contrib/postgres/fields/ranges.py:74:

     def get_prep_value(self, value):
         if value is None:
             return None
         elif isinstance(value, Range):
             return value
         elif isinstance(value, (list, tuple)):
             # Problem is here
 >>>>        return self.range_type(value[0], value[1])
             # Better:    return self.range_type(*value)
         return value
 }}}

 Given that get_prep_value() is calling through to the underlying psycopg2
 object, I'd presume the intention is that the behavior matches the
 underlying psycopg2 semantics.

 Same pattern is found at line 86 in the ```RangeField.to_python()```
 method.

 I realize that by using (*value) it'll change the behavior if someone has
 been passing tuples/list with more than three items, but the behavior
 seems wrong in that case to silently ignore the extra items.  One could be
 more explicit and handle the two-item and three-item tuple/list cases
 individually.  That would minimize the changes.

 There is another case #27147 that is related.  In my experience, Ranges
 generally work correctly and they do have the underlying Postgres behavior
 (eg bounds normalizing for discreet ranges) so I'm not completely clear
 what the issue is that  #27147 is trying to address.

-- 
Ticket URL: <https://code.djangoproject.com/ticket/31872>
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 view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/051.a047f4b08530349c79b353c3dad499ad%40djangoproject.com.

Reply via email to