Repository: googleapis/python-spanner-django

Issue:
django: using F expression with TimeField crashes
Example: `SimulationRun.objects.filter(midpoint__range=[F('start__time'), F('end__time')])`

Traceback:
```
======================================================================
ERROR: test_expressions_in_lookups_join_choice (expressions.tests.IterableLookupInnerExpressionsTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/tim/code/django/tests/expressions/tests.py", line 630, in test_expressions_in_lookups_join_choice
    ordered=False
  File "/home/tim/code/django/django/test/testcases.py", line 1047, in assertQuerysetEqual
    items = map(transform, qs)
  File "/home/tim/code/django/django/db/models/query.py", line 274, in __iter__
    self._fetch_all()
  File "/home/tim/code/django/django/db/models/query.py", line 1242, in _fetch_all
    self._result_cache = list(self._iterable_class(self))
  File "/home/tim/code/django/django/db/models/query.py", line 55, in __iter__
    results = compiler.execute_sql(chunked_fetch=self.chunked_fetch, chunk_size=self.chunk_size)
  File "/home/tim/code/django/django/db/models/sql/compiler.py", line 1127, in execute_sql
    sql, params = self.as_sql()
  File "/home/tim/code/django/django/db/models/sql/compiler.py", line 489, in as_sql
    where, w_params = self.compile(self.where) if self.where is not None else ("", [])
  File "/home/tim/code/django/django/db/models/sql/compiler.py", line 405, in compile
    sql, params = node.as_sql(self, self.connection)
  File "/home/tim/code/django/django/db/models/sql/where.py", line 81, in as_sql
    sql, params = compiler.compile(child)
  File "/home/tim/code/django/django/db/models/sql/compiler.py", line 405, in compile
    sql, params = node.as_sql(self, self.connection)
  File "/home/tim/code/django/django/db/models/lookups.py", line 163, in as_sql
    rhs_sql, rhs_params = self.process_rhs(compiler, connection)
  File "/home/tim/code/django/django/db/models/lookups.py", line 218, in process_rhs
    return self.batch_process_rhs(compiler, connection)
  File "/home/tim/code/django/django/db/models/lookups.py", line 231, in batch_process_rhs
    pre_processed = super().batch_process_rhs(compiler, connection, rhs)
  File "/home/tim/code/django/django/db/models/lookups.py", line 51, in batch_process_rhs
    _, params = self.get_db_prep_lookup(rhs, connection)
  File "/home/tim/code/django/django/db/models/lookups.py", line 186, in get_db_prep_lookup
    if self.get_db_prep_lookup_value_is_iterable else
  File "/home/tim/code/django/django/db/models/lookups.py", line 185, in <listcomp>
    [get_db_prep_value(v, connection, prepared=True) for v in value]
  File "/home/tim/code/django/django/db/models/fields/__init__.py", line 2225, in get_db_prep_value
    return connection.ops.adapt_timefield_value(value)
  File "/home/tim/code/spanner-django/spanner/django/operations.py", line 111, in adapt_timefield_value
    return TimestampStr('0001-01-01T' + value.isoformat(timespec='microseconds') + 'Z')
AttributeError: 'F' object has no attribute 'isoformat'
```


Discussion:

Resolving patch:
diff --git a/spanner/django/features.py b/spanner/django/features.py
--- a/spanner/django/features.py
+++ b/spanner/django/features.py
@@ -185,9 +185,6 @@ class DatabaseFeatures(BaseDatabaseFeatures):
         'expressions.tests.FTimeDeltaTests.test_delta_add',
         'expressions.tests.FTimeDeltaTests.test_duration_with_datetime',
         'expressions.tests.FTimeDeltaTests.test_mixed_comparisons2',
-        # using F expression in range lookup fails:
-        # https://github.com/orijtech/django-spanner/issues/334
-        'expressions.tests.IterableLookupInnerExpressionsTests.test_expressions_in_lookups_join_choice',
         # bitrightshift operator gives incorrect result:
         # https://github.com/orijtech/django-spanner/issues/335
         'expressions.tests.ExpressionOperatorTests.test_lefthand_bitwise_right_shift_operator',
diff --git a/spanner/django/operations.py b/spanner/django/operations.py
--- a/spanner/django/operations.py
+++ b/spanner/django/operations.py
@@ -107,6 +107,9 @@ def adapt_decimalfield_value(self, value, max_digits=None, decimal_places=None):
     def adapt_timefield_value(self, value):
         if value is None:
             return None
+        # Expression values are adapted by the database.
+        if hasattr(value, 'resolve_expression'):
+            return value
         # Column is TIMESTAMP, so prefix a dummy date to the datetime.time.
         return TimestampStr('0001-01-01T' + value.isoformat(timespec='microseconds') + 'Z')
 


Test patch: