Opened 9 years ago
Last modified 9 years ago
#25177 new Bug
Filter reference field on model to a date difference raise a TypeError
Reported by: | Mounir | Owned by: | nobody |
---|---|---|---|
Component: | Database layer (models, ORM) | Version: | 1.8 |
Severity: | Normal | Keywords: | |
Cc: | Triage Stage: | Accepted | |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
I want to filter all products that the start_date and signed_date are lesser than or equal than a specific value.
Before 1.7, I was doing the following:
Product.objects.filter(start_date__isnull=False).extra( where=['"appname_product"."start_date" - "appname_product"."signed_date" <= %s' % days], ).count()
Now, I tried to do the following using F expressions:
Product.objects.filter(start_date__isnull=False).annotate(days=F('start_date')-F('signed_date')).filter(days__lte=days)
The problem, this will raise a TypeError because I think it will try to parse the value to Date:
/usr/local/lib/python2.7/dist-packages/django/db/models/query.pyc in filter(self, *args, **kwargs) 677 set. 678 """ --> 679 return self._filter_or_exclude(False, *args, **kwargs) 680 681 def exclude(self, *args, **kwargs): /usr/local/lib/python2.7/dist-packages/django/db/models/query.pyc in _filter_or_exclude(self, negate, *args, **kwargs) 695 clone.query.add_q(~Q(*args, **kwargs)) 696 else: --> 697 clone.query.add_q(Q(*args, **kwargs)) 698 return clone 699 /usr/local/lib/python2.7/dist-packages/django/db/models/sql/query.pyc in add_q(self, q_object) 1307 existing_inner = set( 1308 (a for a in self.alias_map if self.alias_map[a].join_type == INNER)) -> 1309 clause, require_inner = self._add_q(where_part, self.used_aliases) 1310 self.where.add(clause, AND) 1311 for hp in having_parts: /usr/local/lib/python2.7/dist-packages/django/db/models/sql/query.pyc in _add_q(self, q_object, used_aliases, branch_negated, current_negated, allow_joins, split_subq) 1335 child, can_reuse=used_aliases, branch_negated=branch_negated, 1336 current_negated=current_negated, connector=connector, -> 1337 allow_joins=allow_joins, split_subq=split_subq, 1338 ) 1339 joinpromoter.add_votes(needed_inner) /usr/local/lib/python2.7/dist-packages/django/db/models/sql/query.pyc in build_filter(self, filter_expr, branch_negated, current_negated, can_reuse, connector, allow_joins, split_subq) 1157 clause = self.where_class() 1158 if reffed_expression: -> 1159 condition = self.build_lookup(lookups, reffed_expression, value) 1160 if not condition: 1161 # Backwards compat for custom lookups /usr/local/lib/python2.7/dist-packages/django/db/models/sql/query.pyc in build_lookup(self, lookups, lhs, rhs) 1099 lhs = self.try_transform(lhs, name, lookups) 1100 final_lookup = lhs.get_lookup('exact') -> 1101 return final_lookup(lhs, rhs) 1102 lhs = self.try_transform(lhs, name, lookups) 1103 lookups = lookups[1:] /usr/local/lib/python2.7/dist-packages/django/db/models/lookups.pyc in __init__(self, lhs, rhs) 99 def __init__(self, lhs, rhs): 100 self.lhs, self.rhs = lhs, rhs --> 101 self.rhs = self.get_prep_lookup() 102 if hasattr(self.lhs, 'get_bilateral_transforms'): 103 bilateral_transforms = self.lhs.get_bilateral_transforms() /usr/local/lib/python2.7/dist-packages/django/db/models/lookups.pyc in get_prep_lookup(self) 137 138 def get_prep_lookup(self): --> 139 return self.lhs.output_field.get_prep_lookup(self.lookup_name, self.rhs) 140 141 def get_db_prep_lookup(self, value, connection): /usr/local/lib/python2.7/dist-packages/django/db/models/fields/__init__.pyc in get_prep_lookup(self, lookup_type, value) 1311 if lookup_type in ('month', 'day', 'week_day', 'hour', 'minute', 'second'): 1312 return int(value) -> 1313 return super(DateField, self).get_prep_lookup(lookup_type, value) 1314 1315 def get_prep_value(self, value): /usr/local/lib/python2.7/dist-packages/django/db/models/fields/__init__.pyc in get_prep_lookup(self, lookup_type, value) 725 return value 726 elif lookup_type in ('exact', 'gt', 'gte', 'lt', 'lte'): --> 727 return self.get_prep_value(value) 728 elif lookup_type in ('range', 'in'): 729 return [self.get_prep_value(v) for v in value] /usr/local/lib/python2.7/dist-packages/django/db/models/fields/__init__.pyc in get_prep_value(self, value) 1315 def get_prep_value(self, value): 1316 value = super(DateField, self).get_prep_value(value) -> 1317 return self.to_python(value) 1318 1319 def get_db_prep_value(self, value, connection, prepared=False): /usr/local/lib/python2.7/dist-packages/django/db/models/fields/__init__.pyc in to_python(self, value) 1272 1273 try: -> 1274 parsed = parse_date(value) 1275 if parsed is not None: 1276 return parsed /usr/local/lib/python2.7/dist-packages/django/utils/dateparse.pyc in parse_date(value) 58 Returns None if the input isn't well formatted. 59 """ ---> 60 match = date_re.match(value) 61 if match: 62 kw = {k: int(v) for k, v in six.iteritems(match.groupdict())} TypeError: expected string or buffer
Attachments (1)
Change History (3)
comment:1 by , 9 years ago
Triage Stage: | Unreviewed → Accepted |
---|
comment:2 by , 9 years ago
Note:
See TracTickets
for help on using tickets.
This ticket seems really familiar, but I can't seem to find a duplicate at the moment. I'll keep hunting for it. In the mean time, there's a workaround for what you want to do:
That works on Postgres at least, I'm not sure how other backends handle it.
I think
Combinable._combine()
may need special handling fordate - date
producing durations though.