如何将含jsonb_each_text的PostgreSQL语句转为Django ORM查询?
解决Django ORM调用PostgreSQL jsonb_each_text展开JSONB字段的问题
目标是把这条PostgreSQL语句转成Django ORM查询:
SELECT s.id, jsonb_each_text.key, jsonb_each_text.value FROM survey as s, jsonb_each_text(s.answers);
直接可行的方案:使用RawQuerySet
这是最直接的方式,完全复用原生SQL,避开ORM对函数生成表的限制:
from django.db.models import RawQuerySet # 执行原生查询 results = Survey.objects.raw(""" SELECT s.id, jsonb_each_text.key, jsonb_each_text.value FROM survey as s, jsonb_each_text(s.answers) """) # 遍历结果 for item in results: print(item.id, item.key, item.value)
基于ORM的优化方案:结合Lateral Join(Django 1.11+)
如果想保留ORM的灵活性,可以用Django支持的Lateral Join配合自定义函数:
from django.db.models import Func, F, Lateral from django.db.models.fields import TextField, SlugField # 定义jsonb_each_text函数 class JsonbEachText(Func): function = 'jsonb_each_text' # 声明输出字段的结构 output_fields = [ ('key', SlugField()), ('value', TextField()), ] # 构建Lateral关联查询 answers_lateral = Lateral( JsonbEachText(F('answers')).values('key', 'value') ) # 关联Survey表并查询 survey_results = Survey.objects.annotate( key=F('answers_lateral__key'), value=F('answers_lateral__value'), ).select_related('answers_lateral')
修复你用第三方库的问题
你之前用的第三方库报错,核心问题是JsonbEachText的模板里加了单引号,导致把s.answers当成字符串而非字段引用,修正后即可正常使用:
class JsonbEachText(models.Func): function = 'jsonb_each_text' # 去掉单引号,让表达式作为字段引用 template = "%(function)s(%(expressions)s)" output_fields = [ ('key', models.SlugField()), ('value', models.TextField()), ] class JsonbTable(DynamicFromClauseBaseModel): EXPRESSION_CLASS = JsonbEachText key = models.SlugField(primary_key=True) value = models.TextField() survey_id = models.IntegerField() # 使用F表达式引用Survey的answers字段,而非字符串 result = JsonbTable.objects.fill_expression_with_parameters( F('survey.answers') ).join(Survey, survey_id=Survey.id)
内容的提问来源于stack exchange,提问作者rgilligan
相关产品推荐
相关产品推荐

