我们正在使用 Postgres (v13) 在 Django (v4.0) 中构建一个库。这个库将成为我们公司的核心,所以我们必须小心迁移。当我们为任何物化视图更新基表时,问题出在 Django 迁移上。
class Customer(models.Model):
external_id = models.CharField(max_length=50, unique=True)
class Meta:
db_table = "customer"
class CustomerDetailView(models.Model):
id = models.CharField(max_length=50, primary_key=True)
external_id = models.CharField(max_length=50, unique=True)
class Meta:
managed = False
db_table = "customer_detail_view"
class Migration(migrations.Migration):
...
operations = [
migrations.CreateModel(
name='CustomerDetailView',
fields=[
('id', models.CharField(max_length=50, primary_key=True, serialize=False)),
('external_id', models.CharField(blank=True, max_length=50)),
],
options={
'db_table': 'customer_detail_view',
'managed': False,
},
),
migrations.CreateModel(
name='Customer',
fields=[
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
('external_id', models.CharField(blank=True, max_length=50, null=True, unique=True))
],
options={
'db_table': 'customer',
},
),
class Migration(migrations.Migration):
dependencies = [
("customers", "0001_initial"),
]
operations = [
migrations.RunSQL(
"""
DROP MATERIALIZED VIEW IF EXISTS customer_detail_view;
CREATE MATERIALIZED VIEW customer_detail_view AS
SELECT
cus.id,
cus.external_id,
FROM
customer cus;
CREATE UNIQUE INDEX customer_detail_view_pk ON customer_detail_view(external_id);
""",
"DROP MATERIALIZED VIEW customer_detail_view"
)
]
class Migration(migrations.Migration):
dependencies = [
('customers', '0002_customer_detail_view'),
]
operations = [
migrations.AlterField(
model_name='customer',
name='external_id',
field=models.CharField(blank=True, max_length=60, null=True, unique=True),
),
]
python manage.py migrate
Running migrations:
Applying customers.0003_alter_customer_external_id...Traceback (most recent call last):
File "/usr/app/venv/lib/python3.10/site-packages/django/db/backends/utils.py", line 89, in _execute
return self.cursor.execute(sql, params)
psycopg2.errors.FeatureNotSupported: cannot alter type of a column used by a view or rule
DETAIL: rule _RETURN on materialized view customer_detail_view depends on column "external_id"
我们认为问题与“0001_initial.py”迁移有关,其中 Django(即使物化视图是带有
managed=False
的表)创建迁移,然后在更新基础时无法为创建迁移物化视图。
Django 默认不支持物化视图迁移。这就是为什么你应该手动编写迁移。在删除实体化视图之前,您无法使用字段
Customer
更改模型 external_id
(如果实体化视图是从 Customer
模型和字段 external_id
创建的)。您可以创建自定义迁移以删除物化视图并应用模型更改,然后再次创建您的物化视图。但是有一个简单的解决方案来管理它:
您可以使用此库将物化视图集成到 Django django-materialized-view
你需要的一切:
SELECT *
FROM information_schema.views
WHERE table_schema = 'information_schema'
AND table_name = 'views';