Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 1ec0784

Browse filesBrowse files
authored
feat: enable support for get_key_columns and cleanup tests with unknown failures to specific failures. (#721)
* docs: lint fix for samples * feat: enable foreign key support * feat: add support for spanner fk * feat: disable foreign key as without on delete cascade the db cleanup process fails * fix: add comment as to why foreign key creation is disabled in django * fix: move test_check_constraints_sql_keywords to django3.2 skipped tests * chor: cleanup tests * tests: add failing tests in skipped test
1 parent bfb2e20 commit 1ec0784
Copy full SHA for 1ec0784

File tree

4 files changed

+53
-29
lines changed
Filter options

4 files changed

+53
-29
lines changed

‎README.rst

Copy file name to clipboardExpand all lines: README.rst
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -260,4 +260,4 @@ LIMITATIONS
260260
Spanner has certain limitations of it's own and a full set of limitations are documented over `here <https://cloud.google.com/spanner/quotas#schema_limits>`_
261261
It is recommended that you go through that list.
262262

263-
Django spanner has a set of limitations as well, please go through the `list <https://googleapis.dev/python/django-google-spanner/latest/limitations.html>`_.
263+
Django spanner has a set of limitations as well, please go through the `list <https://github.com/googleapis/python-spanner-django/blob/main/docs/limitations.rst>`_.

‎django_spanner/features.py

Copy file name to clipboardExpand all lines: django_spanner/features.py
+8-20Lines changed: 8 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -61,11 +61,12 @@ class DatabaseFeatures(BaseDatabaseFeatures):
6161

6262
# Django tests that aren't supported by Spanner.
6363
skip_tests = (
64-
# No foreign key constraints in Spanner.
64+
# Spanner does not support very long FK name: 400 Foreign Key name not valid
6565
"backends.tests.FkConstraintsTests.test_check_constraints",
66+
# No foreign key ON DELETE CASCADE in Spanner.
67+
"fixtures_regress.tests.TestFixtures.test_loaddata_raises_error_when_fixture_has_invalid_foreign_key",
6668
# Spanner does not support empty list of DML statement.
6769
"backends.tests.BackendTestCase.test_cursor_executemany_with_empty_params_list",
68-
"fixtures_regress.tests.TestFixtures.test_loaddata_raises_error_when_fixture_has_invalid_foreign_key",
6970
# No Django transaction management in Spanner.
7071
"basic.tests.SelectOnSaveTests.test_select_on_save_lying_update",
7172
# django_spanner monkey patches AutoField to have a default value.
@@ -119,6 +120,7 @@ class DatabaseFeatures(BaseDatabaseFeatures):
119120
"validation.test_validators.TestModelsWithValidators.test_custom_validator_raises_error_for_incorrect_value",
120121
"validation.test_validators.TestModelsWithValidators.test_field_validators_can_be_any_iterable",
121122
# Tests that assume a serial pk.
123+
"servers.tests.LiveServerDatabase.test_fixtures_loaded",
122124
"admin_filters.tests.ListFiltersTests.test_booleanfieldlistfilter_nullbooleanfield",
123125
"admin_filters.tests.ListFiltersTests.test_booleanfieldlistfilter_tuple",
124126
"admin_filters.tests.ListFiltersTests.test_booleanfieldlistfilter",
@@ -283,12 +285,6 @@ class DatabaseFeatures(BaseDatabaseFeatures):
283285
"transaction_hooks.tests.TestConnectionOnCommit.test_inner_savepoint_does_not_affect_outer",
284286
# No sequence for AutoField in Spanner.
285287
"introspection.tests.IntrospectionTests.test_sequence_list",
286-
# DatabaseIntrospection.get_key_columns() is only required if this
287-
# backend needs it (which it currently doesn't).
288-
"introspection.tests.IntrospectionTests.test_get_key_columns",
289-
# DatabaseIntrospection.get_relations() isn't implemented:
290-
# https://github.com/googleapis/python-spanner-django/issues/311
291-
"introspection.tests.IntrospectionTests.test_get_relations",
292288
# pyformat parameters not supported on INSERT:
293289
# https://github.com/googleapis/python-spanner-django/issues/343
294290
"backends.tests.BackendTestCase.test_cursor_execute_with_pyformat",
@@ -375,19 +371,15 @@ class DatabaseFeatures(BaseDatabaseFeatures):
375371
"model_forms.tests.UniqueTest.test_override_unique_together_message",
376372
# os.chmod() doesn't work on Kokoro?
377373
"file_uploads.tests.DirectoryCreationTests.test_readonly_root",
378-
# Tests that sometimes fail on Kokoro for unknown reasons.
374+
# Failing on kokoro but passes locally. Issue: Multiple queries executed expected 1.
379375
"contenttypes_tests.test_models.ContentTypesTests.test_cache_not_shared_between_managers",
380-
"migration_test_data_persistence.tests.MigrationDataNormalPersistenceTestCase.test_persistence",
381-
"servers.test_liveserverthread.LiveServerThreadTest.test_closes_connections",
382-
"servers.tests.LiveServerDatabase.test_fixtures_loaded",
383-
"view_tests.tests.test_csrf.CsrfViewTests.test_no_cookies",
384-
"view_tests.tests.test_csrf.CsrfViewTests.test_no_referer",
385-
"view_tests.tests.test_i18n.SetLanguageTests.test_lang_from_translated_i18n_pattern",
386376
)
387377
if USING_DJANGO_3:
388378
skip_tests += (
389379
# Spanner does not support UUID field natively
390380
"model_fields.test_uuid.TestQuerying.test_iexact",
381+
# Spanner does not support very long FK name: 400 Foreign Key name not valid
382+
"backends.tests.FkConstraintsTests.test_check_constraints_sql_keywords",
391383
# Spanner does not support setting a default value on columns.
392384
"schema.tests.SchemaTests.test_alter_text_field_to_not_null_with_default_value",
393385
# Direct SQL query test that do not follow spanner syntax.
@@ -452,8 +444,6 @@ class DatabaseFeatures(BaseDatabaseFeatures):
452444
# Spanner does not support SELECTing an arbitrary expression that also
453445
# appears in the GROUP BY clause.
454446
"annotations.tests.NonAggregateAnnotationTestCase.test_grouping_by_q_expression_annotation",
455-
# No foreign key constraints in Spanner.
456-
"backends.tests.FkConstraintsTests.test_check_constraints_sql_keywords",
457447
# No Django transaction management in Spanner.
458448
"transactions.tests.DisableDurabiltityCheckTests.test_nested_both_durable",
459449
"transactions.tests.DisableDurabiltityCheckTests.test_nested_inner_durable",
@@ -489,9 +479,7 @@ class DatabaseFeatures(BaseDatabaseFeatures):
489479
"schema.tests.SchemaTests.test_ci_cs_db_collation",
490480
# Spanner limitation: Cannot rename tables and columns.
491481
"migrations.test_operations.OperationTests.test_rename_field_case",
492-
# Tests that sometimes fail on Kokoro for unknown reasons.
493-
"migrations.test_operations.OperationTests.test_add_constraint_combinable",
494-
# Tests that fail but are not related to spanner.
482+
# Warning is not raised, not related to spanner.
495483
"test_utils.test_testcase.TestDataTests.test_undeepcopyable_warning",
496484
)
497485
else:

‎django_spanner/introspection.py

Copy file name to clipboardExpand all lines: django_spanner/introspection.py
+30-5Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -150,11 +150,6 @@ def get_relations(self, cursor, table_name):
150150
"""Return a dictionary of {field_name: (field_name_other_table, other_table)}
151151
representing all the relationships in the table.
152152
153-
TODO: DO NOT USE THIS METHOD UNTIL
154-
https://github.com/googleapis/python-spanner-django/issues/313
155-
is resolved so that foreign keys can be supported, as documented in:
156-
https://github.com/googleapis/python-spanner-django/issues/311
157-
158153
:type cursor: :class:`~google.cloud.spanner_dbapi.cursor.Cursor`
159154
:param cursor: A reference to a Spanner Database cursor.
160155
@@ -348,3 +343,33 @@ def get_constraints(self, cursor, table_name):
348343
constraints[index_name]["unique"] = is_unique
349344

350345
return constraints
346+
347+
def get_key_columns(self, cursor, table_name):
348+
"""
349+
Return a list of (column_name, referenced_table, referenced_column)
350+
for all key columns in the given table.
351+
"""
352+
key_columns = []
353+
cursor.execute(
354+
"""SELECT
355+
tc.COLUMN_NAME as column_name,
356+
ccu.TABLE_NAME as referenced_table,
357+
ccu.COLUMN_NAME as referenced_column
358+
from
359+
INFORMATION_SCHEMA.KEY_COLUMN_USAGE AS tc
360+
JOIN
361+
INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS as rc
362+
ON
363+
tc.CONSTRAINT_NAME = rc.CONSTRAINT_NAME
364+
JOIN
365+
INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE as ccu
366+
ON
367+
rc.CONSTRAINT_NAME = ccu.CONSTRAINT_NAME
368+
WHERE
369+
tc.TABLE_NAME="{table}"
370+
""".format(
371+
table=self.connection.ops.quote_name(table_name)
372+
)
373+
)
374+
key_columns.extend(cursor.fetchall())
375+
return key_columns

‎django_spanner/schema.py

Copy file name to clipboardExpand all lines: django_spanner/schema.py
+14-3Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor):
4141
sql_alter_column_type = "ALTER COLUMN %(column)s %(type)s"
4242

4343
sql_delete_column = "ALTER TABLE %(table)s DROP COLUMN %(column)s"
44+
# Spanner does not suppport ON DELETE CASCADE for foreign keys.
45+
# This can cause failures in django, hence sql_create_inline_fk is disabled.
46+
# sql_create_inline_fk = "CONSTRAINT FK_%(to_table)s_%(to_column)s_%(from_table)s_%(from_column)s FOREIGN KEY (%(from_column_norm)s) REFERENCES %(to_table_norm)s (%(to_column_norm)s)" # noqa
47+
sql_create_inline_fk = None
4448

4549
def create_model(self, model):
4650
"""
@@ -77,14 +81,21 @@ def create_model(self, model):
7781
params.extend(extra_params)
7882
# FK
7983
if field.remote_field and field.db_constraint:
84+
from_table = field.model._meta.db_table
85+
from_column = field.column
8086
to_table = field.remote_field.model._meta.db_table
8187
to_column = field.remote_field.model._meta.get_field(
8288
field.remote_field.field_name
8389
).column
8490
if self.sql_create_inline_fk:
85-
definition += " " + self.sql_create_inline_fk % {
86-
"to_table": self.quote_name(to_table),
87-
"to_column": self.quote_name(to_column),
91+
definition += ", " + self.sql_create_inline_fk % {
92+
"from_table": from_table,
93+
"from_column": from_column,
94+
"to_table": to_table,
95+
"to_column": to_column,
96+
"from_column_norm": self.quote_name(from_column),
97+
"to_table_norm": self.quote_name(to_table),
98+
"to_column_norm": self.quote_name(to_column),
8899
}
89100
elif self.connection.features.supports_foreign_keys:
90101
self.deferred_sql.append(

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.