如何在 Django 模型中集成 postgresql 10/11 声明性 table 分区(即 PARTITION BY 子句)?
How to integrate postgresql 10/11 declarative table partitioning (i.e. PARTITION BY clause) in a Django model?
PostgreSQL 10 引入了 declarative table partitioning 和 PARTITION BY
子句,我想将它用于 Django 模型。
原则上,我需要做的就是在 Django ORM 创建的 CREATE TABLE
语句末尾引入 PARTITION BY
子句。
CREATE TABLE measurement (
city_id int not null,
logdate date not null,
peaktemp int,
unitsales int
) PARTITION BY RANGE (logdate);
是否可以将此子句插入模型中?我认为也许有一种方法可以以某种方式将自定义 SQL 附加到 ORM 生成的查询中,例如使用元数据:
class Measurement(models.Model):
...
class Meta:
append = "PARTITION BY RANGE (logdate)"
据我所知,上述情况是不可能的。我也查看了 architect 库,但它没有使用新的 PARTITION BY 子句。相反,它使用继承和触发器,因此代码没有建议我可以附加子句的任何方式(对于其他数据库也没有,例如 MySQL)。
我还通过添加 ALTER TABLE...
操作来自定义迁移,例如:
operations = [
migrations.RunSQL(
"ALTER TABLE measurement PARTITION BY RANGE (logdate)",
),
]
不幸的是,PostgreSQL 似乎不支持上述(或类似的)ALTER TABLE
statement(至少现在还没有)。
最后一个想法是在发送查询之前检索 Django 模型生成的 CREATE TABLE
语句,例如sql = Measurement.get_statement()
其中 Measurement
是模型。然后,我可以附加 PARTITION BY
子句,并直接发送查询。我找不到 returns 语句的任何方法。我浏览了 Django create_model
code and the sql is generated and directly send to the database,因此从那里提取语句并不容易。
有没有人知道如何以一种我仍然可以利用 Django ORM 的好处的方式实现这一点?
我建议尝试的一种方法是使用 SQL 捕获模式编辑器来收集执行 create_model
所需的 SQL。顺便说一句,这就是 the sqlmigrate
feature 的力量。
from django.db.migrations import CreateModel
class CreatePartitionedModel(CreateModel):
def __init__(self, name, fields, partition_sql, **kwargs):
self.partition_sql = partition_sql
super().__init__(name, fields, **kwargs)
def database_forwards(self, app_label, schema_editor, from_state, to_state):
collector = type(schema_editor)(
schema_editor.connection, collect_sql=True, atomic=False
)
with collector:
super().database_forwards(
app_label, collector, from_state, to_state
)
collected_sql = collector.collected_sql
schema_editor.deferred_sql.extend(
collector.deferred_sql
)
model = to_state.apps.get_model(app_label, self.name)
create_table = 'CREATE TABLE %s' % schema_editor.quote_name(
model._meta.db_table
)
for sql in collected_sql:
if str(sql).startswith(create_table):
sql = '%s PARTITION BY %s' % (sql.rstrip(';'), self.partition_sql)
schema_editor.execute(sql)
从那时起,您只需将 makemigrations
自动生成的 CreateModel
替换为 CreatePartitionedModel
操作,并确保指定 partition_sql='RANGE (logdate)'
。
PostgreSQL 10 引入了 declarative table partitioning 和 PARTITION BY
子句,我想将它用于 Django 模型。
原则上,我需要做的就是在 Django ORM 创建的 CREATE TABLE
语句末尾引入 PARTITION BY
子句。
CREATE TABLE measurement (
city_id int not null,
logdate date not null,
peaktemp int,
unitsales int
) PARTITION BY RANGE (logdate);
是否可以将此子句插入模型中?我认为也许有一种方法可以以某种方式将自定义 SQL 附加到 ORM 生成的查询中,例如使用元数据:
class Measurement(models.Model):
...
class Meta:
append = "PARTITION BY RANGE (logdate)"
据我所知,上述情况是不可能的。我也查看了 architect 库,但它没有使用新的 PARTITION BY 子句。相反,它使用继承和触发器,因此代码没有建议我可以附加子句的任何方式(对于其他数据库也没有,例如 MySQL)。
我还通过添加 ALTER TABLE...
操作来自定义迁移,例如:
operations = [
migrations.RunSQL(
"ALTER TABLE measurement PARTITION BY RANGE (logdate)",
),
]
不幸的是,PostgreSQL 似乎不支持上述(或类似的)ALTER TABLE
statement(至少现在还没有)。
最后一个想法是在发送查询之前检索 Django 模型生成的 CREATE TABLE
语句,例如sql = Measurement.get_statement()
其中 Measurement
是模型。然后,我可以附加 PARTITION BY
子句,并直接发送查询。我找不到 returns 语句的任何方法。我浏览了 Django create_model
code and the sql is generated and directly send to the database,因此从那里提取语句并不容易。
有没有人知道如何以一种我仍然可以利用 Django ORM 的好处的方式实现这一点?
我建议尝试的一种方法是使用 SQL 捕获模式编辑器来收集执行 create_model
所需的 SQL。顺便说一句,这就是 the sqlmigrate
feature 的力量。
from django.db.migrations import CreateModel
class CreatePartitionedModel(CreateModel):
def __init__(self, name, fields, partition_sql, **kwargs):
self.partition_sql = partition_sql
super().__init__(name, fields, **kwargs)
def database_forwards(self, app_label, schema_editor, from_state, to_state):
collector = type(schema_editor)(
schema_editor.connection, collect_sql=True, atomic=False
)
with collector:
super().database_forwards(
app_label, collector, from_state, to_state
)
collected_sql = collector.collected_sql
schema_editor.deferred_sql.extend(
collector.deferred_sql
)
model = to_state.apps.get_model(app_label, self.name)
create_table = 'CREATE TABLE %s' % schema_editor.quote_name(
model._meta.db_table
)
for sql in collected_sql:
if str(sql).startswith(create_table):
sql = '%s PARTITION BY %s' % (sql.rstrip(';'), self.partition_sql)
schema_editor.execute(sql)
从那时起,您只需将 makemigrations
自动生成的 CreateModel
替换为 CreatePartitionedModel
操作,并确保指定 partition_sql='RANGE (logdate)'
。