web-dev-qa-db-ja.com

heroku、postgreSQL、Django、コメント、tastypie:指定された名前と引数の型に一致する演算子はありません。明示的な型キャストを追加する必要があるかもしれません

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

20
arctelix

IMSoPの回答に基づく:これは、Generic外部キーが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)に変換するだけで済みました。 s。

4
arctelix

PostgreSQLは「強く型付け」されています。つまり、すべてのクエリのすべての値には、明示的に(たとえば、テーブルの列の型)または暗黙的に(たとえば、WHERE句に入力された値)のいずれかで定義された特定の型があります。 )。 _=_を含むすべての関数と演算子は、特定の型を受け入れるものとして定義する必要があります。たとえば、_VarChar = VarChar_には演算子があり、_int = int_には別の演算子があります。

あなたのケースでは、int型として明示的に定義されている列がありますが、PostgreSQLがtext型として解釈した値と比較しています。

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

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

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

32
IMSoP

ORMをハックしないようにするには、外部ソフトウェアpostgresを使用して、独自のキャストを登録し、操作を比較できます。 同様の質問の例をご覧ください

0
Hubbitus