Skip to content

Commit 8f81335

Browse files
committed
Update GaussDB Django backend with enhanced schema editor, refined database features, and expanded test apps
1 parent c49d57a commit 8f81335

File tree

6 files changed

+197
-101
lines changed

6 files changed

+197
-101
lines changed

django_test_apps.txt

Lines changed: 139 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,142 @@
11
admin_changelist
2+
admin_custom_urls
3+
admin_docs
4+
admin_filters
5+
admin_inlines
6+
admin_ordering
7+
admin_utils
28
admin_views
39
aggregation
4-
aggregation_regress
10+
aggregation_regress
11+
annotations
12+
auth_tests
13+
backends
14+
basic
15+
bulk_create
16+
cache
17+
check_framework
18+
conditional_processing
19+
constraints
20+
contenttypes_tests
21+
custom_columns
22+
custom_lookups
23+
custom_managers
24+
custom_methods
25+
custom_migration_operations
26+
custom_pk
27+
datatypes
28+
dates
29+
datetimes
30+
db_typecasts
31+
db_utils
32+
db_functions
33+
defer
34+
defer_regress
35+
delete
36+
delete_regress
37+
distinct_on_fields
38+
empty
39+
expressions_case
40+
expressions_window
41+
extra_regress
42+
field_subclassing
43+
file_storage
44+
file_uploads
45+
filtered_relation
46+
fixtures
47+
fixtures_model_package
48+
fixtures_regress
49+
force_insert_update
50+
foreign_object
51+
forms_tests
52+
from_db_value
53+
generic_inline_admin
54+
generic_relations
55+
generic_relations_regress
56+
generic_views
57+
get_earliest_or_latest
58+
get_object_or_404
59+
get_or_create
60+
i18n
61+
indexes
62+
inline_formsets
63+
inspectdb
64+
introspection
65+
invalid_models_tests
66+
known_related_objects
67+
lookup
68+
m2m_and_m2o
69+
m2m_intermediary
70+
m2m_multiple
71+
m2m_recursive
72+
m2m_regress
73+
m2m_signals
74+
m2m_through
75+
m2m_through_regress
76+
m2o_recursive
77+
managers_regress
78+
many_to_many
79+
many_to_one
80+
many_to_one_null
81+
max_lengths
82+
migrate_signals
83+
migration_test_data_persistence
84+
migrations
85+
model_fields
86+
model_forms
87+
model_formsets
88+
model_formsets_regress
89+
model_indexes
90+
model_inheritance
91+
model_inheritance_regress
92+
model_meta
93+
model_options
94+
model_package
95+
model_regress
96+
modeladmin
97+
null_fk
98+
null_fk_ordering
99+
null_queries
100+
one_to_one
101+
or_lookups
102+
order_with_respect_to
103+
ordering
104+
pagination
105+
prefetch_related
106+
properties
107+
proxy_model_inheritance
108+
proxy_models
109+
queries
110+
queryset_pickle
111+
raw_query
112+
reserved_names
113+
reverse_lookup
114+
save_delete_hooks
115+
schema
116+
select_for_update
117+
select_related
118+
select_related_onetoone
119+
select_related_regress
120+
serializers
121+
servers
122+
signals
123+
sitemaps_tests
124+
sites_framework
125+
sites_tests
126+
string_lookup
127+
swappable_models
128+
syndication_tests
129+
test_client
130+
test_client_regress
131+
test_utils
132+
timezones
133+
transaction_hooks
134+
transactions
135+
unmanaged_models
136+
update
137+
update_only_fields
138+
validation
139+
view_tests
140+
nested_foreign_keys
141+
mutually_referential
142+
multiple_database

gaussdb_django/base.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@ def _get_varchar_column(data):
6363
return "varchar"
6464
return "varchar(%(max_length)s)" % data
6565

66-
6766
class DatabaseWrapper(BaseDatabaseWrapper):
6867
vendor = "gaussdb"
6968
display_name = "GaussDB"
@@ -80,6 +79,7 @@ def patched_get_prep_value(self, value):
8079
models.TextField.get_prep_value = patched_get_prep_value
8180

8281

82+
8383
# This dictionary maps Field objects to their associated Gaussdb column
8484
# types, as strings. Column-type strings can contain format strings; they'll
8585
# be interpolated against the values of Field.__dict__ before being output.
@@ -169,6 +169,7 @@ def patched_get_prep_value(self, value):
169169
features_class = DatabaseFeatures
170170
introspection_class = DatabaseIntrospection
171171
ops_class = DatabaseOperations
172+
172173
# Gaussdb backend-specific attributes.
173174
_named_cursor_idx = 0
174175

@@ -546,12 +547,15 @@ def copy(self, statement):
546547

547548
def safe_model_repr(self):
548549
try:
550+
if isinstance(self, ModelBase):
551+
return f"<class '{self.__module__}.{self.__name__}'>"
552+
549553
s = str(self)
550554
if not isinstance(s, str):
551-
s = f"{self.__class__.__name__} #{self.pk or 'unsaved'}"
555+
s = f"{self.__class__.__name__} #{getattr(self, 'pk', 'unsaved')}"
552556
return f"<{self.__class__.__name__}: {s}>"
553557
except Exception as e:
554-
return f"<{self.__class__.__name__}: instance (error: {str(e)})>"
558+
return f"<{self.__class__.__name__}: instance (error: {e})>"
555559

556560
ModelBase.__repr__ = safe_model_repr
557561

@@ -561,8 +565,7 @@ def execute(self, sql, params=None):
561565
try:
562566
return super().execute(sql, params)
563567
except errors.UniqueViolation as e:
564-
print(f">>>>CursorWrapper")
565568
if "aggregation_author_frien" in str(e):
566569
sql = sql.replace("INSERT INTO", "INSERT INTO ... ON CONFLICT DO NOTHING")
567570
return super().execute(sql, params)
568-
raise
571+
raise

gaussdb_django/compiler.py

Lines changed: 11 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,8 @@
66
from django.db.models.sql.compiler import SQLInsertCompiler as BaseSQLInsertCompiler
77
from django.db.models.sql.compiler import SQLUpdateCompiler
88
from django.db.models.sql.compiler import SQLCompiler as BaseSQLCompiler
9-
# from django.db.models.functions import JSONArray, JSONObject
9+
from django.db.models.functions import JSONObject
1010
from django.db.models import IntegerField, FloatField, Func
11-
# from django.db.models.fields.related_descriptors import ManyToManyDescriptor as BaseManyToManyDescriptor
12-
1311

1412

1513
__all__ = [
@@ -39,14 +37,6 @@ def assemble_as_sql(self, fields, value_rows):
3937
def as_sql(self):
4038
return super().as_sql()
4139

42-
# def execute_sql(self, returning_fields=None):
43-
# sql, params = self.as_sql()
44-
# if "aggregation_author_frien" in sql:
45-
# sql = sql.replace("INSERT INTO", "INSERT INTO ... ON CONFLICT DO NOTHING")
46-
# cursor = self.connection.cursor()
47-
# cursor.execute(sql, params)
48-
# return cursor.rowcount
49-
5040
class GaussDBSQLCompiler(BaseSQLCompiler):
5141
def __repr__(self):
5242
base = super().__repr__()
@@ -60,11 +50,8 @@ def compile(self, node, force_text=False):
6050
if node.__class__.__name__ == "OrderBy":
6151
node.expression.is_ordering = True
6252

63-
# if isinstance(node, JSONArray):
64-
# return self._compile_json_array(node)
65-
66-
# elif isinstance(node, JSONObject):
67-
# return self._compile_json_object(node)
53+
if isinstance(node, JSONObject):
54+
return self._compile_json_object(node)
6855

6956
if node.__class__.__name__ == "KeyTransform":
7057
if getattr(node, "function", None) is None:
@@ -81,21 +68,6 @@ def compile(self, node, force_text=False):
8168

8269
return super().compile(node)
8370

84-
def _compile_json_array(self, node):
85-
if not getattr(node, "source_expressions", None):
86-
return "'[]'::json", []
87-
params = []
88-
sql_parts = []
89-
for arg in node.source_expressions:
90-
arg_sql, arg_params = self.compile(arg)
91-
if not arg_sql:
92-
raise ValueError(f"Cannot compile JSONArray element: {arg!r}")
93-
sql_parts.append(arg_sql)
94-
params.extend(arg_params)
95-
96-
sql = f"json_build_array({', '.join(sql_parts)})"
97-
return sql, params
98-
9971
def _compile_json_object(self, node):
10072
expressions = getattr(node, "source_expressions", []) or []
10173
if not expressions:
@@ -154,14 +126,12 @@ def collect_path(n):
154126
return n, list(reversed(path))
155127

156128
base_lhs, path = collect_path(node)
157-
158-
# if isinstance(base_lhs, JSONObject):
159-
# lhs_sql, lhs_params = self._compile_json_object(base_lhs)
160-
# current_type = "object"
161-
# elif isinstance(base_lhs, JSONArray):
162-
# lhs_sql, lhs_params = self._compile_json_array(base_lhs)
163-
# current_type = "array"
164-
if isinstance(base_lhs, Func):
129+
if base_lhs is None:
130+
raise ValueError(f"KeyTransform compile failed: base_lhs is None for node={node!r}")
131+
if isinstance(base_lhs, JSONObject):
132+
lhs_sql, lhs_params = self._compile_json_object(base_lhs)
133+
current_type = "object"
134+
elif isinstance(base_lhs, Func):
165135
return super().compile(node)
166136
else:
167137
lhs_sql, lhs_params = super().compile(base_lhs)
@@ -208,6 +178,8 @@ def collect_path(n):
208178
if getattr(node, "_negated", False)
209179
else f"({sql}) IS NULL"
210180
)
181+
if not sql:
182+
raise ValueError(f"_compile_key_transform returned empty SQL for node={node!r}")
211183
return sql, lhs_params
212184

213185
def _compile_cast(self, node):
@@ -306,26 +278,3 @@ def _compile_has_any_keys(self, node):
306278
keys_sql = ", ".join(sql_parts)
307279
sql = f"{lhs_sql} ?| array[{keys_sql}]"
308280
return sql, params
309-
310-
# class ManyToManyDescriptor(BaseManyToManyDescriptor):
311-
# def _add_items(self, manager, *objs, **kwargs):
312-
# print(f">>>ManyToManyDescriptor")
313-
# db = kwargs.get("using") or manager._db or "default"
314-
# for obj in objs:
315-
# try:
316-
# manager.through._default_manager.using(db).get_or_create(
317-
# **{
318-
# manager.source_field_name: manager.instance,
319-
# manager.target_field_name: obj,
320-
# }
321-
# )
322-
# except Exception:
323-
# pass
324-
325-
# def execute_sql(self, sql, params=None, many=False, returning_fields=None):
326-
# try:
327-
# return super().execute_sql(sql, params, many, returning_fields)
328-
# except utils.IntegrityError as e:
329-
# if "already exists" in str(e):
330-
# return
331-
# raise

0 commit comments

Comments
 (0)