21

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を書かずにこのエラーを回避した経験のある人はいますか?

4

3 に答える 3

36

WHEREPostgreSQL は「厳密に型指定」されています。つまり、すべてのクエリのすべての値は、明示的に (テーブル内の列の型など) または暗黙的に (句に入力される値など) 定義された特定の型を持ちます。を含むすべての関数と演算子は、=特定の型を受け入れるように定義する必要があります。たとえば、 には演算子があり、 にVarChar = VarCharは別の演算子がありますint = int

あなたの場合、 type として明示的に定義された列がありますintが、それを PostgreSQL が type として解釈した値と比較していますtext

一方、SQLite は「弱い型付け」です。値は、実行されるアクションに最も適した型として自由に扱われます。したがって、開発用 SQLite データベースでは、PostgreSQL が の特定の定義を必要とする(または、PostgreSQL の無制限の文字列の型である)操作'42' = 42を問題なく計算できます。VarChar = inttext = inttext

現在、PostgreSQL が役立つ場合があり、型が既知の演算子と一致するように値を自動的に「キャスト」しますが、多くの場合、ヒントにあるように、明示的に行う必要があります。SQL を自分で書いている場合、明示的な型のケースはWHERE id = CAST('42' AS INT)(またはWHERE CAST(id AS text) = '42') のようになります。

そうではないので、クエリ ジェネレータに与える入力が実際の整数であることを確認する必要があります。たまたま数字で構成される文字列ではありません。これはfields.IntegerFieldではなくを使用するのと同じくらい簡単fields.CharFieldだと思いますが、実際には Django も Python も知らないので、そこから理解できることを願って背景を説明したいと思います。

于 2013-04-16T22:03:52.543 に答える
7

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

もともと、チャールズが行ったのと同様に SQL を変更する方法を探していましたが、クエリを 2 つの部分に分割し、str(id) を int(id) に変換するだけで済みました。秒。

于 2013-04-17T04:24:28.973 に答える