Repository: googleapis/python-spanner-django

Issue:
django-test-suite: reject in code tables with long names e.g. in backends test suite
Mandated by Cloud Spanner in 
https://cloud.google.com/spanner/quotas#tables and 
![spanner-table-restrictions](https://user-images.githubusercontent.com/4898263/71944119-9cd07d80-3177-11ea-8b7c-fc226b20a42b.png)

we should upfront reject tables with very long names beyond 128 characters e.g. the failing test in test suite `backends`
`backends_verylongmodelnamezzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz_m2m_also_quite_long_zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz`

which fails as follows
<details>

```shell
Synchronizing apps without migrations:
  Creating tables...
    Creating table django_content_type
    Creating table auth_permission
    Creating table auth_group
    Creating table auth_user
    Creating table django_session
    Creating table backends_square
    Creating table backends_person
    Creating table backends_schoolclass
    Creating table backends_verylongmodelnamezzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
    Creating table backends_tag
    Creating table CaseSensitive_Post
    Creating table backends_reporter
    Creating table backends_article
    Creating table backends_item
    Creating table backends_object
    Creating table backends_objectreference
    Creating table backends_rawdata
    Creating table backends_author
    Creating table backends_book
    Running deferred SQL...
Running migrations:
Traceback (most recent call last):
  File "runtests.py", line 507, in <module>
    options.exclude_tags,
  File "runtests.py", line 294, in django_tests
    extra_tests=extra_tests,
  File "/home/emmanuel/Desktop/spanner-orm/django_tests/django/django/test/runner.py", line 629, in run_tests
    old_config = self.setup_databases(aliases=databases)
  File "/home/emmanuel/Desktop/spanner-orm/django_tests/django/django/test/runner.py", line 554, in setup_databases
    self.parallel, **kwargs
  File "/home/emmanuel/Desktop/spanner-orm/django_tests/django/django/test/utils.py", line 174, in setup_databases
    serialize=connection.settings_dict.get('TEST', {}).get('SERIALIZE', True),
  File "/home/emmanuel/.local/lib/python3.7/site-packages/spanner/django/creation.py", line 27, in create_test_db
    super().create_test_db(*args, **kwargs)
  File "/home/emmanuel/Desktop/spanner-orm/django_tests/django/django/db/backends/base/creation.py", line 72, in create_test_db
    run_syncdb=True,
  File "/home/emmanuel/Desktop/spanner-orm/django_tests/django/django/core/management/__init__.py", line 148, in call_command
    return command.execute(*args, **defaults)
  File "/home/emmanuel/Desktop/spanner-orm/django_tests/django/django/core/management/base.py", line 364, in execute
    output = self.handle(*args, **options)
  File "/home/emmanuel/Desktop/spanner-orm/django_tests/django/django/core/management/base.py", line 83, in wrapped
    res = handle_func(*args, **kwargs)
  File "/home/emmanuel/Desktop/spanner-orm/django_tests/django/django/core/management/commands/migrate.py", line 234, in handle
    fake_initial=fake_initial,
  File "/home/emmanuel/Desktop/spanner-orm/django_tests/django/django/db/migrations/executor.py", line 91, in migrate
    self.recorder.ensure_schema()
  File "/home/emmanuel/Desktop/spanner-orm/django_tests/django/django/db/migrations/recorder.py", line 62, in ensure_schema
    if self.has_table():
  File "/home/emmanuel/Desktop/spanner-orm/django_tests/django/django/db/migrations/recorder.py", line 56, in has_table
    return self.Migration._meta.db_table in self.connection.introspection.table_names(self.connection.cursor())
  File "/home/emmanuel/Desktop/spanner-orm/django_tests/django/django/db/backends/base/introspection.py", line 48, in table_names
    return get_names(cursor)
  File "/home/emmanuel/Desktop/spanner-orm/django_tests/django/django/db/backends/base/introspection.py", line 43, in get_names
    return sorted(ti.name for ti in self.get_table_list(cursor)
  File "/home/emmanuel/.local/lib/python3.7/site-packages/spanner/django/introspection.py", line 16, in get_table_list
    """)
  File "/home/emmanuel/Desktop/spanner-orm/django_tests/django/django/db/backends/utils.py", line 67, in execute
    return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)
  File "/home/emmanuel/Desktop/spanner-orm/django_tests/django/django/db/backends/utils.py", line 76, in _execute_with_wrappers
    return executor(sql, params, many, context)
  File "/home/emmanuel/Desktop/spanner-orm/django_tests/django/django/db/backends/utils.py", line 82, in _execute
    return self.cursor.execute(sql)
  File "/home/emmanuel/.local/lib/python3.7/site-packages/spanner/dbapi/cursor.py", line 91, in execute
    self.__handle_DQL(sql, args or None)
  File "/home/emmanuel/.local/lib/python3.7/site-packages/spanner/dbapi/cursor.py", line 161, in __handle_DQL
    self.__commit_preceding_batch(OP_DQL)
  File "/home/emmanuel/.local/lib/python3.7/site-packages/spanner/dbapi/cursor.py", line 156, in __commit_preceding_batch
    return self.__db_handle.commit(OP_DQL)
  File "/home/emmanuel/.local/lib/python3.7/site-packages/spanner/dbapi/connection.py", line 48, in commit
    self.__check_or_flush_update_ddl(last_op)
  File "/home/emmanuel/.local/lib/python3.7/site-packages/spanner/dbapi/connection.py", line 110, in __check_or_flush_update_ddl
    return self.__update_ddl(ddl_statements)
  File "/home/emmanuel/.local/lib/python3.7/site-packages/spanner/dbapi/connection.py", line 85, in __update_ddl
    return self.__dbhandle.update_ddl(ddl_statements).result()
  File "/home/emmanuel/.local/lib/python3.7/site-packages/google/api_core/future/polling.py", line 127, in result
    raise self._exception
google.api_core.exceptions.GoogleAPICallError: None Table name not valid: backends_verylongmodelnamezzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz_m2m_also_quite_long_zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz.

real	0m23.146s
user	0m3.738s
sys	0m1.186s
```
</details>


Discussion:

Resolving patch:
diff --git a/spanner/django/operations.py b/spanner/django/operations.py
--- a/spanner/django/operations.py
+++ b/spanner/django/operations.py
@@ -35,6 +35,10 @@ class DatabaseOperations(BaseDatabaseOperations):
         'iso_year': 'isoyear',
     }
 
+    def max_name_length(self):
+        # https://cloud.google.com/spanner/quotas#tables
+        return 128
+
     def quote_name(self, name):
         # Spanner says "column name not valid" if spaces or hyphens are present
         # (although according the docs, any character should be allowed in


Test patch: