Skip to content

Commit 9fd79b2

Browse files
committed
Create indexes defined in Meta.indexes for materialized views
1 parent c0e96aa commit 9fd79b2

File tree

4 files changed

+51
-11
lines changed

4 files changed

+51
-11
lines changed

django_pgviews/models.py

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -68,12 +68,7 @@ def run_backlog(self, backlog, *, force, update, materialized_views_check_sql_ch
6868
try:
6969
if isinstance(view_cls(), MaterializedView):
7070
status = create_materialized_view(
71-
connection,
72-
view_cls._meta.db_table,
73-
view_cls.get_sql(),
74-
concurrent_index=view_cls._concurrent_index,
75-
with_data=view_cls.with_data,
76-
check_sql_changed=materialized_views_check_sql_changed,
71+
connection, view_cls, check_sql_changed=materialized_views_check_sql_changed
7772
)
7873
else:
7974
status = create_view(
@@ -106,7 +101,7 @@ def run_backlog(self, backlog, *, force, update, materialized_views_check_sql_ch
106101
elif status == "FORCED":
107102
msg = "forced overwrite of existing schema"
108103
elif status == "FORCE_REQUIRED":
109-
msg = "exists with incompatible schema, " "--force required to update"
104+
msg = "exists with incompatible schema, --force required to update"
110105
else:
111106
msg = status
112107

django_pgviews/view.py

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -96,9 +96,7 @@ def _drop_mat_view(cursor, view_name):
9696

9797

9898
@transaction.atomic()
99-
def create_materialized_view(
100-
connection, view_name, view_query: ViewSQL, concurrent_index=None, with_data=True, check_sql_changed=False
101-
):
99+
def create_materialized_view(connection, view_cls, check_sql_changed=False):
102100
"""
103101
Create a materialized view on a connection.
104102
@@ -110,6 +108,16 @@ def create_materialized_view(
110108
already with the same SQL, if there is, it will not do anything. Otherwise the materialized view gets dropped
111109
and recreated.
112110
"""
111+
view_name = view_cls._meta.db_table
112+
view_query = view_cls.get_sql()
113+
concurrent_index = view_cls._concurrent_index
114+
115+
try:
116+
schema_name = connection.schema_name
117+
schema_name_log = f"schema {schema_name}"
118+
except AttributeError:
119+
schema_name_log = "default schema"
120+
113121
vschema, vname = _schema_and_name(connection, view_name)
114122

115123
cursor_wrapper = connection.cursor()
@@ -146,13 +154,24 @@ def create_materialized_view(
146154

147155
if view_exists:
148156
_drop_mat_view(cursor, view_name)
157+
log.info("pgview dropped materialized view %s (%s)", view_name, schema_name_log)
158+
159+
_create_mat_view(cursor, view_name, query, view_query.params, with_data=view_cls.with_data)
160+
log.info("pgview created materialized view %s (%s)", view_name, schema_name_log)
149161

150-
_create_mat_view(cursor, view_name, query, view_query.params, with_data=with_data)
151162
if concurrent_index is not None:
152163
index_sub_name = "_".join([s.strip() for s in concurrent_index.split(",")])
153164
cursor.execute(
154165
"CREATE UNIQUE INDEX {0}_{1}_index ON {0} ({2})".format(view_name, index_sub_name, concurrent_index)
155166
)
167+
log.info("pgview created concurrent index on view %s (%s)", view_name, schema_name_log)
168+
169+
if view_cls._meta.indexes:
170+
schema_editor = connection.schema_editor()
171+
172+
for index in view_cls._meta.indexes:
173+
schema_editor.add_index(view_cls, index)
174+
log.info("pgview created index %s on view %s (%s)", index.name, view_name, schema_name_log)
156175

157176
if view_exists:
158177
return "UPDATED"

tests/test_project/test_project/viewtest/models.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,10 @@ class MaterializedRelatedViewWithIndex(view.ReadOnlyMaterializedView):
6363
sql = """SELECT id AS model_id, id FROM viewtest_testmodel"""
6464
model = models.ForeignKey(TestModel, on_delete=models.DO_NOTHING)
6565

66+
class Meta:
67+
managed = False
68+
indexes = [models.Index(fields=["model"])]
69+
6670

6771
class CustomSchemaView(view.ReadOnlyView):
6872
sql = """SELECT id AS model_id, id FROM viewtest_testmodel"""

tests/test_project/test_project/viewtest/tests.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,28 @@ def test_materialized_view(self):
132132
"Materialized view should have updated concurrently",
133133
)
134134

135+
def test_materialized_view_indexes(self):
136+
args = [
137+
models.MaterializedRelatedViewWithIndex._meta.db_table,
138+
"viewtest_materializedrelatedviewwithindex_id_index",
139+
]
140+
141+
with connection.cursor() as cursor:
142+
cursor.execute(
143+
"SELECT COUNT(*) FROM pg_indexes WHERE tablename = %s AND indexname = %s",
144+
args,
145+
)
146+
id_index_count = cursor.fetchone()[0]
147+
148+
cursor.execute(
149+
"SELECT COUNT(*) FROM pg_indexes WHERE tablename = %s AND indexname != %s",
150+
args,
151+
)
152+
other_index_count = cursor.fetchone()[0]
153+
154+
self.assertEqual(id_index_count, 1)
155+
self.assertEqual(other_index_count, 1)
156+
135157
def test_materialized_view_with_no_data(self):
136158
"""
137159
Test a materialized view with no data works correctly

0 commit comments

Comments
 (0)