Repository: googleapis/python-spanner-django

Issue:
django: lookups with multiple target fields fail
3 test failures out of 13. The failing tests fail with
```shell
django.core.exceptions.FieldError: The relation has multiple target fields, but only single target field was asked for
```
as per
```shell
======================================================================
ERROR: test_deep_mixed_backward (foreign_object.test_agnostic_order_trimjoin.TestLookupQuery)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/emmanuelodeke/Desktop/django-spanner/dmt/django/tests/foreign_object/test_agnostic_order_trimjoin.py", line 27, in test_deep_mixed_backward
    attrgetter('id')
  File "/Users/emmanuelodeke/Desktop/django-spanner/django_tests/django/django/test/testcases.py", line 1047, in assertQuerysetEqual
    items = map(transform, qs)
  File "/Users/emmanuelodeke/Desktop/django-spanner/django_tests/django/django/db/models/query.py", line 274, in __iter__
    self._fetch_all()
  File "/Users/emmanuelodeke/Desktop/django-spanner/django_tests/django/django/db/models/query.py", line 1242, in _fetch_all
    self._result_cache = list(self._iterable_class(self))
  File "/Users/emmanuelodeke/Desktop/django-spanner/django_tests/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 "/Users/emmanuelodeke/Desktop/django-spanner/django_tests/django/django/db/models/sql/compiler.py", line 1127, in execute_sql
    sql, params = self.as_sql()
  File "/Users/emmanuelodeke/Desktop/django-spanner/django_tests/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 "/Users/emmanuelodeke/Desktop/django-spanner/django_tests/django/django/db/models/sql/compiler.py", line 405, in compile
    sql, params = node.as_sql(self, self.connection)
  File "/Users/emmanuelodeke/Desktop/django-spanner/django_tests/django/django/db/models/sql/where.py", line 81, in as_sql
    sql, params = compiler.compile(child)
  File "/Users/emmanuelodeke/Desktop/django-spanner/django_tests/django/django/db/models/sql/compiler.py", line 403, in compile
    sql, params = vendor_impl(self, self.connection)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/django_spanner/lookups.py", line 116, in cast_param_to_float
    elif (hasattr(self.lhs.output_field, 'target_field') and
  File "/Users/emmanuelodeke/Desktop/django-spanner/django_tests/django/django/db/models/fields/related.py", line 437, in target_field
    "The relation has multiple target fields, but only single target field was asked for")
django.core.exceptions.FieldError: The relation has multiple target fields, but only single target field was asked for

======================================================================
ERROR: test_prefetch_foreignkey_reverse_works (foreign_object.tests.MultiColumnFKTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/emmanuelodeke/Desktop/django-spanner/dmt/django/tests/foreign_object/tests.py", line 199, in test_prefetch_foreignkey_reverse_works
    for p in Person.objects.order_by('pk')
  File "/Users/emmanuelodeke/Desktop/django-spanner/dmt/django/tests/foreign_object/tests.py", line 199, in <listcomp>
    for p in Person.objects.order_by('pk')
  File "/Users/emmanuelodeke/Desktop/django-spanner/django_tests/django/django/db/models/query.py", line 274, in __iter__
    self._fetch_all()
  File "/Users/emmanuelodeke/Desktop/django-spanner/django_tests/django/django/db/models/query.py", line 1242, in _fetch_all
    self._result_cache = list(self._iterable_class(self))
  File "/Users/emmanuelodeke/Desktop/django-spanner/django_tests/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 "/Users/emmanuelodeke/Desktop/django-spanner/django_tests/django/django/db/models/sql/compiler.py", line 1127, in execute_sql
    sql, params = self.as_sql()
  File "/Users/emmanuelodeke/Desktop/django-spanner/django_tests/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 "/Users/emmanuelodeke/Desktop/django-spanner/django_tests/django/django/db/models/sql/compiler.py", line 405, in compile
    sql, params = node.as_sql(self, self.connection)
  File "/Users/emmanuelodeke/Desktop/django-spanner/django_tests/django/django/db/models/sql/where.py", line 81, in as_sql
    sql, params = compiler.compile(child)
  File "/Users/emmanuelodeke/Desktop/django-spanner/django_tests/django/django/db/models/sql/compiler.py", line 403, in compile
    sql, params = vendor_impl(self, self.connection)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/django_spanner/lookups.py", line 116, in cast_param_to_float
    elif (hasattr(self.lhs.output_field, 'target_field') and
  File "/Users/emmanuelodeke/Desktop/django-spanner/django_tests/django/django/db/models/fields/related.py", line 437, in target_field
    "The relation has multiple target fields, but only single target field was asked for")
django.core.exceptions.FieldError: The relation has multiple target fields, but only single target field was asked for

======================================================================
ERROR: test_reverse_query_returns_correct_result (foreign_object.tests.MultiColumnFKTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/emmanuelodeke/Desktop/django-spanner/dmt/django/tests/foreign_object/tests.py", line 70, in test_reverse_query_returns_correct_result
    membership = self.bob.membership_set.get()
  File "/Users/emmanuelodeke/Desktop/django-spanner/django_tests/django/django/db/models/manager.py", line 82, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "/Users/emmanuelodeke/Desktop/django-spanner/django_tests/django/django/db/models/query.py", line 402, in get
    num = len(clone)
  File "/Users/emmanuelodeke/Desktop/django-spanner/django_tests/django/django/db/models/query.py", line 256, in __len__
    self._fetch_all()
  File "/Users/emmanuelodeke/Desktop/django-spanner/django_tests/django/django/db/models/query.py", line 1242, in _fetch_all
    self._result_cache = list(self._iterable_class(self))
  File "/Users/emmanuelodeke/Desktop/django-spanner/django_tests/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 "/Users/emmanuelodeke/Desktop/django-spanner/django_tests/django/django/db/models/sql/compiler.py", line 1127, in execute_sql
    sql, params = self.as_sql()
  File "/Users/emmanuelodeke/Desktop/django-spanner/django_tests/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 "/Users/emmanuelodeke/Desktop/django-spanner/django_tests/django/django/db/models/sql/compiler.py", line 405, in compile
    sql, params = node.as_sql(self, self.connection)
  File "/Users/emmanuelodeke/Desktop/django-spanner/django_tests/django/django/db/models/sql/where.py", line 81, in as_sql
    sql, params = compiler.compile(child)
  File "/Users/emmanuelodeke/Desktop/django-spanner/django_tests/django/django/db/models/sql/compiler.py", line 403, in compile
    sql, params = vendor_impl(self, self.connection)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/django_spanner/lookups.py", line 116, in cast_param_to_float
    elif (hasattr(self.lhs.output_field, 'target_field') and
  File "/Users/emmanuelodeke/Desktop/django-spanner/django_tests/django/django/db/models/fields/related.py", line 437, in target_field
    "The relation has multiple target fields, but only single target field was asked for")
django.core.exceptions.FieldError: The relation has multiple target fields, but only single target field was asked for

----------------------------------------------------------------------
Ran 33 tests in 409.782s

FAILED (errors=3)
Destroying test database for alias 'default' ('test_idde4695779383be1c7b8')...
```

and please find in this link the whole replay log consisting of all the SQL statements and their params https://gist.github.com/odeke-em/ef00d6ed1bf9ea22990500a73af8e47f


Discussion:

Resolving patch:
diff --git a/django_spanner/lookups.py b/django_spanner/lookups.py
--- a/django_spanner/lookups.py
+++ b/django_spanner/lookups.py
@@ -122,10 +122,10 @@ def cast_param_to_float(self, compiler, connection):
         if isinstance(self.lhs.output_field, DecimalField):
             params[0] = float(params[0])
         # Cast remote field lookups that must be integer but come in as string.
-        elif (hasattr(self.lhs.output_field, 'target_field') and
-                self.lhs.output_field.target_field.rel_db_type(connection) == 'INT64' and
-                isinstance(params[0], str)):
-            params[0] = int(params[0])
+        elif hasattr(self.lhs.output_field, 'get_path_info'):
+            for i, field in enumerate(self.lhs.output_field.get_path_info()[-1].target_fields):
+                if field.rel_db_type(connection) == 'INT64' and isinstance(params[i], str):
+                    params[i] = int(params[i])
     return sql, params
 
 


Test patch:
diff --git a/django_test_apps.txt b/django_test_apps.txt
--- a/django_test_apps.txt
+++ b/django_test_apps.txt
@@ -33,6 +33,7 @@ file_storage
 file_uploads
 fixtures
 fixtures_model_package
+foreign_object
 from_db_value
 get_earliest_or_latest
 get_object_or_404