heroku,postgreSQL,django,comments,tastypie:没有运算符匹配给定的名称和参数类型。您可能需要添加显式类型转换

时间:2013-04-16 18:48:13

标签: django postgresql heroku tastypie django-comments

我对django的内置注释模型进行了简单查询,并使用heroku的postgreSQL数据库获取下面的错误:

DatabaseError: operator does not exist: integer = text LINE 1: 
... INNER JOIN "django_comments" ON ("pi ns_pin"."id" = "django_...
                                                         ^
HINT:  No operator matches the given name and argument type(s). 
You might need to add explicit type casts.

在谷歌搜索之后似乎这个错误在django之前已经多次被解决,但我仍然得到它(所有相关问题都在3 - 5年前关闭)。我正在使用django 1.4版和最新版本的tastypie。

查询是在orm过滤器下进行的,并且与我的开发数据库(sqlite3)完美配合:

class MyResource(ModelResource):    

    comments = fields.ToManyField('my.api.api.CmntResource', 'comments', full=True, null=True)

    def build_filters(self, filters=None):
        if filters is None:
            filters = {}

        orm_filters = super(MyResource, self).build_filters(filters)

        if 'cmnts' in filters:
            orm_filters['comments__user__id__exact'] = filters['cmnts']

class CmntResource(ModelResource):
    user = fields.ToOneField('my.api.api.UserResource', 'user', full=True)
    site_id = fields.CharField(attribute = 'site_id')
    content_object = GenericForeignKeyField({
        My: MyResource,
    }, 'content_object')
    username = fields.CharField(attribute = 'user__username', null=True)
    user_id = fields.CharField(attribute = 'user__id', null=True)

有没有人在没有编写原始SQL的情况下解决此错误的经验?

3 个答案:

答案 0 :(得分:32)

PostgreSQL是“强类型”的 - 也就是说,每个查询中的每个值都有一个特定的类型,要么显式定义(例如表中列的类型),要么隐式定义(例如输入{{1}的值}子句)。所有函数和运算符(包括WHERE)都必须定义为接受特定类型 - 例如,=有一个运算符,VarChar = VarChar有一个运算符。

在您的情况下,您有一个显式定义为类型int = int的列,但您将它与PostgreSQL解释为类型int的值进行比较。

另一方面,SQLite是“弱类型” - 值可以自由地被视为最适合正在执行的操作的任何类型。因此,在您的开发SQLite数据库中,可以很好地计算操作text,其中PostgreSQL需要'42' = 42的特定定义(或VarChar = inttext = int是无界的类型PostgreSQL中的字符串)。

现在,PostgreSQL将有时有用并自动“强制转换”您的值以使类型与已知运算符匹配,但更常见的是,正如提示所示,您需要明确地执行此操作。如果您自己编写SQL,则显式类型的情况可能看起来像text(或WHERE id = CAST('42' AS INT))。

既然你没有,你需要确保你给查询生成器的输入是一个实际的整数,而不仅仅是一个恰好由数字组成的字符串。我怀疑这就像使用WHERE CAST(id AS text) = '42'而不是fields.IntegerField一样简单,但我实际上并不知道Django,甚至Python,所以我想我会给你背景,希望你能拿走从那里开始。

答案 1 :(得分:4)

基于IMSoP的回答:当通用外键使用object_id的文本字段且对象的id字段不是文本字段时,这是django的ORM层的限制。 Django不想做任何假设或将对象的id转换为不是。我在http://charlesleifer.com/blog/working-around-django-s-orm-to-do-interesting-things-with-gfks/找到了一篇很好的文章。

该文章的作者Charles Leifer为受此影响的查询提出了一个非常酷的解决方案,对于解决此问题非常有用。

或者,我设法让我的查询工作如下:

if 'cmnts' in filters:
    comments = Comment.objects.filter(user__id=filters['cmnts'], content_type__name = 'my',   site_id=settings.SITE_ID ).values_list('object_pk', flat=True)
    comments = [int(c) for c in comments]
    orm_filters['pk__in'] = comments

最初我正在寻找一种类似于Charles所做的修改SQL的方法,但事实证明我所要做的就是将查询分成两部分并将str(id)转换为int( ID)的

答案 2 :(得分:0)

不要破解你ORM和外部软件postgres允许你注册自己的演员阵容并比较操作。 Please look example in similar question