自定义 PostgreSQL 查询执行到 django 应用程序

Posted

技术标签:

【中文标题】自定义 PostgreSQL 查询执行到 django 应用程序【英文标题】:custom PostgreSQL query execute to django app 【发布时间】:2019-08-06 00:00:51 【问题描述】:

我在 django 应用程序中使用 postgres/postgis 数据库的应用程序有两个具有一对多关系的模型。 我在数据库和 pgadmin 面板中创建了一个不容易的查询并且工作正常。

这里是查询:

select string_agg(distinct app_work.id::text, ', ') AS code_work,string_agg(distinct app_work.stage, ', ') 
AS stage,string_agg(distinct app_work.dfield_work, ', ') AS dfield,app_point.geom  
from app_point, app_work where app_point.id=app_work.point_field_id GROUP BY app_point.id;

现在我想在我的 django 应用程序中使用这个查询(我需要这个查询的结果)来创建 geojson 或 json 导出。 我不确定如何使用 django 方法对象和查询转换此查询(例如 point.objects.all())我尝试使用这样的自定义 postgres 查询:

models.py

class point(models.Model):
    geom = models.MultiPointField(srid=4326)
    objects = models.GeoManager()

    def __unicode__(self):
        return str(self.id)

    class meta:
        verbose_name_plural="point_info"


class work(models.Model):
        dfield_work = models.CharField(max_length=100,blank=True, null=True)
    stage = models.CharField(max_length=100,blank=True, null=True)
    field1 = models.CharField(max_length=100,blank=True, null=True)
    field2 = models.CharField(max_length=100,blank=True, null=True)
    point_field= models.ForeignKey('point', blank=True, null=True)

    def __unicode__(self):
        return str(self.id)

vews.py

from django.db import connection


def points(request):
    cursor = connection.cursor()
    cursor.execute("""seselect string_agg(distinct app_work.id::text, ', ') AS code_work,string_agg(distinct app_work.stage, ', ') 
AS stage,string_agg(distinct app_work.dfield_work, ', ') AS dfield,app_point.geom  
from app_point, app_work where app_point.id=app_work.point_field_id GROUP BY app_point.id from log_point, log_work where log_point.id=log_work.point_field_id GROUP BY log_point.id""")
    row = cursor.fetchall()
    print row
    data = serialize('geojson', row)
    return HttpResponse(data,content_type='json')

在打印行中我得到了正确的列表结果

但不工作,我有这个错误:

'tuple' object has no attribute '_meta'

知道怎么解决吗?

【问题讨论】:

该错误来自哪一行? @HenryWoody 如果我访问此链接,该错误会在浏览器的页面中显示给我。有什么想法吗? 我认为即使在浏览器中仍然应该有错误的回溯,但如果没有,您能否包含来自运行服务器的控制台/终端的回溯? 还有serialize定义在哪里? 请求方法:GET 请求 URL:127.0.0.1:8000/data Django 版本:1.11.3 异常类型:AttributeError 异常值:'tuple' 对象没有属性 '_meta' 异常位置:Python27\Lib\site- package\django\contrib\gis\serializers\geojson.py in start_object,第 35 行,如果对你有帮助我在 views.py 中使用此代码 【参考方案1】:

您可以使用 cursor.execute(raw_query) 在 django 应用程序上执行查询。

sample_query = 'SELET COUNT(*) FROM operation_084'
cursor = connection.cursor()
cursor.execute(sample_query)

【讨论】:

【参考方案2】:
    SELECT "id", "LchMatchedTradeRef", "abc" from operation_091 
    UNION 
    SELECT "id", "LchMatchedTradeRef", '' abc FROM operation_084

当您需要在 Django 应用程序中运行此查询时, 你需要像下面这样跟随。

    empty_var = "''"
    raw_query = 'SELECT "id", "LchMatchedTradeRef", "abc" FROM operation_091 UNION SELECT "id", "LchMatchedTradeRef", ' + empty_var + ' abc FROM operation_084'

    cursor = connection.cursor()
    cursor.execute(raw_query)

【讨论】:

【参考方案3】:

Django geojson serialize 方法需要一个查询集(从用法 here in the docs 可以看出)而不是一个元组。从source 中,我们可以看到Serializer(JSONSerializer) 类旨在“将查询集转换为GeoJSON”并期望它可以调用._meta 的对象(即Django 模型)。因此,当您将元组(cursor.fetchall() 的输出)传递给 serialize 时,您会收到错误 'tuple' object has no attribute '_meta'

由于您使用的是原始 SQL 查询,因此实际上不需要使用 geojson 序列化程序,因为它旨在将 Python 对象转换为 JSON。您可以改为将 SQL 查询的输出转换为 JSON 并将其作为响应发送。

这是一个例子:

import json
from django.db import connection
from django.http import HttpResponse


query_text = """
SELECT
    string_agg(distinct app_work.id::text, ', ') AS code_work,
    string_agg(distinct app_work.stage, ', ') AS stage,
    string_agg(distinct app_work.dfield_work, ', ') AS dfield,
    app_point.geom
FROM
    app_point, app_work
WHERE
    app_point.id = app_work.point_field_id
GROUP BY
    app_point.id;
"""

def points(request):
    with connection.cursor() as cursor:
        cursor.execute(query_text)
        data = dictfetchall(cursor)

    stringified_data = json.dumps(data)
    return HttpResponse(stringified_data, content_type="application/json")


def dictfetchall(cursor):
    "Return all rows from a cursor as a dict"
    columns = [col[0] for col in cursor.description]
    return [
        dict(zip(columns, row))
        for row in cursor.fetchall()
    ]

(来自Django SQL docs的dictfetchall

上面代码中有几点需要注意:

    这是相当重要的:使用with 作为cursor,以便在我们完成对数据库的查询后关闭连接。您也可以手动关闭连接,但with 语句会为我们处理。

    使用 dictfetchall 函数,我们将 SQL 查询的输出转换为 Python 字典(准备好成为 JSON)。无需使用 Django 序列化程序,因为我们使用的是原始 Python 数据类型而不是 Python 对象或 Django 模型。

【讨论】:

不是我在浏览器中出现此错误In order to allow non-dict objects to be serialized set the safe parameter to False。在行return JsonResponse(data) @Mar 哦,对了,因为data 将是一个列表,而不是字典,你必须设置safe=False 我会更新。 @Mar 实际上改为HttpResponse,但在发送前调用json.dumpssafe=False 标志有点吓人 你的工作看起来很棒,但它不是geojson而是一个简单的json @Mar 你用的是什么数据库?

以上是关于自定义 PostgreSQL 查询执行到 django 应用程序的主要内容,如果未能解决你的问题,请参考以下文章

postgresql自动导出SQL语句查出的数据

PostgreSQL父子建表查询所有的子数据-利用自定义函数查询

PostgreSQL父子建表查询所有的子数据-利用自定义函数查询

执行自定义函数时 Postgresql 错误 42883

在 C# 中保存绑定到 DataGrid 的自定义 sql 查询中的数据

PostgreSQL——查询重写——定义规则