在Django中创建PostgreSQL视图存储QuerySet中间结果的实现方案
Django创建PostgreSQL视图实现中间查询结果复用的方案
核心逻辑是将你需要复用的QuerySet对应的SQL转换为数据库视图,再通过Django只读模型映射视图,就能直接复用中间查询结果。
第一步:获取QuerySet对应的原生SQL
先提取你需要存为视图的查询的原生SQL,后续建视图直接使用:
elements = Element.objects.filter(is_active=True, eventcardad__isnull=False) # 打印输出即可拿到完整的原生查询语句 print(elements.query)
第二步:通过自定义迁移创建视图
Django没有内置创建视图的ORM接口,我们可以通过空迁移执行原生SQL来实现:
- 先生成空迁移文件:
python manage.py makemigrations 你的应用名 --empty - 打开生成的迁移文件,填入视图创建/回滚逻辑:
from django.db import migrations class Migration(migrations.Migration): dependencies = [ # 替换为你应用里上一个迁移的文件名 ('你的应用名', '000x_xxxx'), ] operations = [ migrations.RunSQL( # 建视图语句,AS后面替换为第一步拿到的原生SQL sql=""" CREATE OR REPLACE VIEW active_element_view AS SELECT * FROM element WHERE is_active = true AND eventcardad_id IS NOT NULL; """, # 回滚时删除视图的语句 reverse_sql="DROP VIEW IF EXISTS active_element_view;" ) ]
- 执行迁移完成视图创建:
python manage.py migrate
如果需要把查询结果物理存储提升查询性能,可以把上面的CREATE OR REPLACE VIEW改为CREATE MATERIALIZED VIEW创建物化视图,需要更新结果时执行REFRESH MATERIALIZED VIEW active_element_view;即可。
第三步:创建映射视图的只读模型
创建一个和视图字段完全匹配的Django模型,设置为非托管模式避免Django修改视图结构:
class ActiveElementView(models.Model): # 字段和你原Element模型的字段、或者查询返回的字段完全对应即可 is_active = models.BooleanField() eventcardad = models.ForeignKey(EventCardAd, on_delete=models.DO_NOTHING) # 其他你需要的Element字段都在此处补充定义 class Meta: managed = False db_table = 'active_element_view' # 和你创建的视图名称保持一致
第四步:复用视图查询结果
后续要用到之前的中间查询结果时,直接操作这个映射模型即可,不需要重复写过滤逻辑:
# 直接查询视图,等价于复用了你之前的过滤结果 elements_from_view = ActiveElementView.objects.all() # 也可以继续加其他过滤、关联查询逻辑 filtered_elements = ActiveElementView.objects.filter(xxxx)
注意:普通视图是虚拟表,每次查询都会执行底层的查询逻辑;物化视图会物理存储结果,性能更高,但需要手动刷新数据。视图本身是只读的,不能对映射模型执行写、更新、删除操作。
内容的提问来源于stack exchange,提问作者Park jinhong
相关产品推荐
相关产品推荐

