diff --git a/.github/workflows/test-python.yml b/.github/workflows/test-python.yml index f7052f5fc..9f72d969e 100644 --- a/.github/workflows/test-python.yml +++ b/.github/workflows/test-python.yml @@ -71,7 +71,7 @@ jobs: aggregation_regress annotations auth_tests.test_models.UserManagerTestCase - backends.base.test_base.DatabaseWrapperTests + backends basic bulk_create dates @@ -85,6 +85,7 @@ jobs: defer defer_regress from_db_value + introspection known_related_objects lookup m2m_and_m2o @@ -110,8 +111,7 @@ jobs: ordering or_lookups queries - schema.tests.SchemaTests.test_creation_deletion - schema.tests.SchemaTests.test_db_table + schema select_related select_related_onetoone select_related_regress diff --git a/django_mongodb/features.py b/django_mongodb/features.py index 2aa8217dc..5e6dd984b 100644 --- a/django_mongodb/features.py +++ b/django_mongodb/features.py @@ -4,20 +4,28 @@ class DatabaseFeatures(BaseDatabaseFeatures): allow_sliced_subqueries_with_in = False + can_create_inline_fk = False + can_introspect_foreign_keys = False greatest_least_ignores_nulls = True has_json_object_function = False has_native_json_field = True + supports_collation_on_charfield = False + supports_column_check_constraints = False supports_date_lookup_using_string = False supports_explaining_query_execution = True + supports_expression_indexes = False supports_foreign_keys = False supports_ignore_conflicts = False supports_json_field_contains = False # BSON Date type doesn't support microsecond precision. supports_microsecond_precision = False + supports_paramstyle_pyformat = False supports_select_difference = False supports_select_intersection = False # Not implemented: https://github.com/mongodb-labs/django-mongodb/issues/72 supports_select_union = False + supports_sequence_reset = False + supports_table_check_constraints = False supports_temporal_subtraction = True # MongoDB stores datetimes in UTC. supports_timezones = False @@ -72,6 +80,89 @@ class DatabaseFeatures(BaseDatabaseFeatures): "many_to_one.tests.ManyToOneTests.test_selects", # Incorrect JOIN with GenericRelation gives incorrect results. "aggregation_regress.tests.AggregationTests.test_aggregation_with_generic_reverse_relation", + # subclasses of BaseDatabaseWrapper may require an is_usable() method + "backends.tests.BackendTestCase.test_is_usable_after_database_disconnects", + # Connection creation doesn't follow the usual Django API. + "backends.tests.ThreadTests.test_pass_connection_between_threads", + "backends.tests.ThreadTests.test_closing_non_shared_connections", + "backends.tests.ThreadTests.test_default_connection_thread_local", + # AddField + "schema.tests.SchemaTests.test_add_datefield_and_datetimefield_use_effective_default", + "schema.tests.SchemaTests.test_add_field", + "schema.tests.SchemaTests.test_add_field_binary", + "schema.tests.SchemaTests.test_add_field_both_defaults_preserves_db_default", + "schema.tests.SchemaTests.test_add_field_default_dropped", + "schema.tests.SchemaTests.test_add_field_default_nullable", + "schema.tests.SchemaTests.test_add_field_default_transform", + "schema.tests.SchemaTests.test_add_field_durationfield_with_default", + "schema.tests.SchemaTests.test_add_field_o2o_nullable", + "schema.tests.SchemaTests.test_add_field_temp_default", + "schema.tests.SchemaTests.test_add_field_temp_default_boolean", + "schema.tests.SchemaTests.test_add_field_use_effective_default", + "schema.tests.SchemaTests.test_add_text_field_with_db_default", + "schema.tests.SchemaTests.test_add_textfield_default_nullable", + # RemoveField + "schema.tests.SchemaTests.test_remove_field", + "schema.tests.SchemaTests.test_remove_indexed_field", + # Add/RemoveIndex + "schema.tests.SchemaTests.test_add_remove_index", + "schema.tests.SchemaTests.test_composed_desc_index_with_fk", + "schema.tests.SchemaTests.test_composed_index_with_fk", + "schema.tests.SchemaTests.test_create_index_together", + "schema.tests.SchemaTests.test_order_index", + "schema.tests.SchemaTests.test_text_field_with_db_index", + # AlterField + "schema.tests.SchemaTests.test_alter", + "schema.tests.SchemaTests.test_alter_auto_field_to_integer_field", + "schema.tests.SchemaTests.test_alter_field_add_index_to_integerfield", + "schema.tests.SchemaTests.test_alter_field_default_dropped", + "schema.tests.SchemaTests.test_alter_field_fk_keeps_index", + "schema.tests.SchemaTests.test_alter_field_fk_to_o2o", + "schema.tests.SchemaTests.test_alter_field_o2o_keeps_unique", + "schema.tests.SchemaTests.test_alter_field_o2o_to_fk", + "schema.tests.SchemaTests.test_alter_int_pk_to_int_unique", + "schema.tests.SchemaTests.test_alter_not_unique_field_to_primary_key", + "schema.tests.SchemaTests.test_alter_null_to_not_null", + "schema.tests.SchemaTests.test_alter_null_to_not_null_keeping_default", + "schema.tests.SchemaTests.test_alter_primary_key_the_same_name", + "schema.tests.SchemaTests.test_autofield_to_o2o", + # AlterField (rename) + "schema.tests.SchemaTests.test_rename", + "schema.tests.SchemaTests.test_rename_keep_db_default", + "schema.tests.SchemaTests.test_rename_keep_null_status", + # AlterField (db_index) + "schema.tests.SchemaTests.test_indexes", + "schema.tests.SchemaTests.test_remove_constraints_capital_letters", + "schema.tests.SchemaTests.test_remove_db_index_doesnt_remove_custom_indexes", + # AlterField (unique) + "schema.tests.SchemaTests.test_remove_field_unique_does_not_remove_meta_constraints", + "schema.tests.SchemaTests.test_unique", + "schema.tests.SchemaTests.test_unique_and_reverse_m2m", + # alter_index_together + "schema.tests.SchemaTests.test_index_together", + "schema.tests.SchemaTests.test_remove_index_together_does_not_remove_meta_indexes", + # alter_unique_together + "schema.tests.SchemaTests.test_remove_unique_together_does_not_remove_meta_constraints", + "schema.tests.SchemaTests.test_unique_together", + # ManyToManyField + "schema.tests.SchemaTests.test_m2m", + "schema.tests.SchemaTests.test_m2m_create", + "schema.tests.SchemaTests.test_m2m_create_custom", + "schema.tests.SchemaTests.test_m2m_create_inherited", + "schema.tests.SchemaTests.test_m2m_custom", + "schema.tests.SchemaTests.test_m2m_inherited", + "schema.tests.SchemaTests.test_m2m_rename_field_in_target_model", + "schema.tests.SchemaTests.test_m2m_repoint", + "schema.tests.SchemaTests.test_m2m_repoint_custom", + "schema.tests.SchemaTests.test_m2m_repoint_inherited", + "schema.tests.SchemaTests.test_m2m_through_alter", + "schema.tests.SchemaTests.test_m2m_through_alter_custom", + "schema.tests.SchemaTests.test_m2m_through_alter_inherited", + "schema.tests.SchemaTests.test_m2m_through_remove", + # add/remove_constraint + "schema.tests.SchemaTests.test_composed_constraint_with_fk", + "schema.tests.SchemaTests.test_remove_ignored_unique_constraint_not_create_fk_index", + "schema.tests.SchemaTests.test_unique_constraint", } # $bitAnd, #bitOr, and $bitXor are new in MongoDB 6.3. _django_test_expected_failures_bitwise = { @@ -92,6 +183,9 @@ def django_test_expected_failures(self): return expected_failures django_test_skips = { + "Database defaults aren't supported by MongoDB.": { + "schema.tests.SchemaTests.test_db_default_output_field_resolving", + }, "Insert expressions aren't supported.": { "bulk_create.tests.BulkCreateTests.test_bulk_insert_now", "bulk_create.tests.BulkCreateTests.test_bulk_insert_expressions", @@ -115,6 +209,7 @@ def django_test_expected_failures(self): "model_fields.test_uuid.TestQuerying.test_startswith", }, "QuerySet.prefetch_related() is not supported on MongoDB.": { + "backends.base.test_creation.TestDeserializeDbFromString.test_serialize_db_to_string_base_manager_with_prefetch_related", "m2m_through_regress.test_multitable.MultiTableTests.test_m2m_prefetch_proxied", "m2m_through_regress.test_multitable.MultiTableTests.test_m2m_prefetch_reverse_proxied", "many_to_many.tests.ManyToManyTests.test_add_after_prefetch", @@ -127,6 +222,7 @@ def django_test_expected_failures(self): }, "AutoField not supported.": { "bulk_create.tests.BulkCreateTests.test_bulk_insert_nullable_fields", + "introspection.tests.IntrospectionTests.test_sequence_list", "lookup.tests.LookupTests.test_filter_by_reverse_related_field_transform", "lookup.tests.LookupTests.test_in_ignore_none_with_unhashable_items", "m2m_through_regress.tests.ThroughLoadDataTestCase.test_sequence_creation", @@ -337,6 +433,7 @@ def django_test_expected_failures(self): "aggregation.tests.AggregateTestCase.test_dates_with_aggregation", "annotations.tests.AliasTests.test_dates_alias", "aggregation_regress.tests.AggregationTests.test_more_more_more2", + "backends.tests.DateQuotingTest.test_django_date_trunc", "dates.tests.DatesTests.test_dates_trunc_datetime_fields", "dates.tests.DatesTests.test_related_model_traverse", "many_to_one.tests.ManyToOneTests.test_select_related", @@ -417,10 +514,25 @@ def django_test_expected_failures(self): "lookup.tests.LookupTests.test_textfield_exact_null", "queries.tests.ExistsSql.test_exists", "queries.tests.Queries6Tests.test_col_alias_quoted", + "schema.tests.SchemaTests.test_rename_column_renames_deferred_sql_references", + "schema.tests.SchemaTests.test_rename_table_renames_deferred_sql_references", }, "Test executes raw SQL.": { "aggregation.tests.AggregateTestCase.test_coalesced_empty_result_set", "annotations.tests.NonAggregateAnnotationTestCase.test_raw_sql_with_inherited_field", + "backends.base.test_base.ExecuteWrapperTests", + "backends.tests.BackendTestCase.test_cursor_contextmanager", + "backends.tests.BackendTestCase.test_cursor_executemany", + "backends.tests.BackendTestCase.test_cursor_executemany_with_empty_params_list", + "backends.tests.BackendTestCase.test_cursor_executemany_with_iterator", + "backends.tests.BackendTestCase.test_duplicate_table_error", + "backends.tests.BackendTestCase.test_queries", + "backends.tests.BackendTestCase.test_queries_bare_where", + "backends.tests.BackendTestCase.test_queries_limit", + "backends.tests.BackendTestCase.test_queries_logger", + "backends.tests.BackendTestCase.test_unicode_fetches", + "backends.tests.EscapingChecks", + "backends.test_utils.CursorWrapperTests", "delete_regress.tests.DeleteLockingTest.test_concurrent_delete", "expressions.tests.BasicExpressionsTests.test_annotate_values_filter", "expressions.tests.BasicExpressionsTests.test_filtering_on_rawsql_that_is_boolean", @@ -429,6 +541,7 @@ def django_test_expected_failures(self): "model_fields.test_jsonfield.TestQuerying.test_key_transform_raw_expression", "model_fields.test_jsonfield.TestQuerying.test_nested_key_transform_raw_expression", "queries.tests.Queries1Tests.test_order_by_rawsql", + "schema.test_logging.SchemaLoggerTests.test_extra_args", "timezones.tests.LegacyDatabaseTests.test_cursor_execute_accepts_naive_datetime", "timezones.tests.LegacyDatabaseTests.test_cursor_execute_returns_naive_datetime", "timezones.tests.LegacyDatabaseTests.test_raw_sql", @@ -497,6 +610,24 @@ def django_test_expected_failures(self): "db_functions.comparison.test_cast.CastTests.test_cast_from_python_to_datetime", "db_functions.comparison.test_cast.CastTests.test_cast_to_duration", }, + "DatabaseIntrospection.get_table_description() not supported.": { + "introspection.tests.IntrospectionTests.test_bigautofield", + "introspection.tests.IntrospectionTests.test_get_table_description_col_lengths", + "introspection.tests.IntrospectionTests.test_get_table_description_names", + "introspection.tests.IntrospectionTests.test_get_table_description_nullable", + "introspection.tests.IntrospectionTests.test_get_table_description_types", + "introspection.tests.IntrospectionTests.test_smallautofield", + }, + "DatabaseIntrospection.get_constraints() not implemented.": { + "introspection.tests.IntrospectionTests.test_get_constraints", + "introspection.tests.IntrospectionTests.test_get_constraints_index_types", + "introspection.tests.IntrospectionTests.test_get_constraints_indexes_orders", + "introspection.tests.IntrospectionTests.test_get_constraints_unique_indexes_orders", + "introspection.tests.IntrospectionTests.test_get_primary_key_column", + }, + "MongoDB can't introspect primary key.": { + "schema.tests.SchemaTests.test_primary_key", + }, "Known issue querying JSONField.": { # An ExpressionWrapper annotation with KeyTransform followed by # .filter(expr__isnull=False) doesn't use KeyTransformIsNull as it @@ -519,9 +650,23 @@ def django_test_expected_failures(self): "queries.test_q.QCheckTests", "queries.test_query.TestQueryNoModel", }, + "MongoDB doesn't use CursorDebugWrapper.": { + "backends.tests.LastExecutedQueryTest.test_last_executed_query", + "backends.tests.LastExecutedQueryTest.test_last_executed_query_with_duplicate_params", + "backends.tests.LastExecutedQueryTest.test_query_encoding", + }, "Test not applicable for MongoDB's SQLCompiler.": { "queries.test_iterator.QuerySetIteratorTests", }, + "Support for views not implemented.": { + "introspection.tests.IntrospectionTests.test_table_names_with_views", + }, + "Connection health checks not implemented.": { + "backends.base.test_base.ConnectionHealthChecksTests", + }, + "transaction.atomic() is not supported.": { + "backends.base.test_base.DatabaseWrapperLoggingTests", + }, } @cached_property diff --git a/django_mongodb/introspection.py b/django_mongodb/introspection.py index 76b5b460b..59cb1f41a 100644 --- a/django_mongodb/introspection.py +++ b/django_mongodb/introspection.py @@ -3,4 +3,4 @@ class DatabaseIntrospection(BaseDatabaseIntrospection): def table_names(self, cursor=None, include_views=False): - return [x["name"] for x in self.connection.database.list_collections()] + return sorted([x["name"] for x in self.connection.database.list_collections()]) diff --git a/django_mongodb/operations.py b/django_mongodb/operations.py index 61d0b482c..bf5ed8bb8 100644 --- a/django_mongodb/operations.py +++ b/django_mongodb/operations.py @@ -175,7 +175,7 @@ def execute_sql_flush(self, tables): collection = self.connection.database[table] options = collection.options() if not options.get("capped", False): - collection.drop() + collection.delete_many({}) def prep_lookup_value(self, value, field, lookup): """