wake-up-neo.com

heroku, postgreSQL, Django, Kommentare, tastypie: Kein Operator entspricht dem angegebenen Namen und den angegebenen Argumenttypen. Möglicherweise müssen Sie explizite Typumwandlungen hinzufügen

Ich habe eine einfache Abfrage über das eingebaute Kommentarmodell von Django und den folgenden Fehler mit der postgreSQL-Datenbank von Heroku:

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.

Nach dem googeln scheint es, als sei dieser Fehler in Django schon oft angesprochen worden, aber ich bekomme ihn immer noch (alle damit verbundenen Probleme wurden vor 3-5 Jahren geschlossen). Ich verwende Django Version 1.4 und die neueste Version von Tastypie.

Die Abfrage erfolgt unter orm-Filtern und funktioniert perfekt mit meiner Entwicklungsdatenbank (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)

Hat jemand Erfahrung damit, diesen Fehler zu umgehen, ohne Raw SQL zu schreiben?

19
arctelix

Auf der Antwort von IMSoP aufbauen: Dies ist eine Einschränkung von Djangos ORM-Layer, wenn ein generischer Fremdschlüssel ein Textfeld für object_id verwendet und das ID-Feld des Objekts kein Textfeld ist. Django möchte keine Annahmen machen oder die ID des Objekts als etwas definieren, das es nicht ist. Ich habe einen hervorragenden Artikel zu diesem http://charlesleifer.com/blog/working-around-Django-s-orm-to-do-interesting-things-with-gfks/ gefunden.

Der Autor des Artikels, Charles Leifer, hat eine sehr coole Lösung für Abfragen gefunden, die davon betroffen sind, und wird bei der Bewältigung dieses Problems sehr nützlich sein.

Alternativ ist es mir gelungen, meine Abfrage wie folgt auszuführen:

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

Ursprünglich war ich auf der Suche nach einer Möglichkeit, die SQL zu ändern, ähnlich wie es Charles getan hat, aber es stellte sich heraus, dass ich nur die Abfrage in zwei Teile aufteilen und die str (id) in int (id) umwandeln musste. ' s.

4
arctelix

PostgreSQL ist "stark typisiert" - das heißt, jeder Wert in jeder Abfrage hat einen bestimmten Typ, der entweder explizit definiert ist (z. B. der Typ einer Spalte in einer Tabelle) oder implizit (z. B. die in eine Variable WHERE eingegebenen Werte). Alle Funktionen und Operatoren, einschließlich =, müssen so definiert sein, dass sie bestimmte Typen akzeptieren. So gibt es beispielsweise einen Operator für VarChar = VarChar und einen anderen für int = int.

In Ihrem Fall haben Sie eine Spalte, die explizit als Typ int definiert ist, aber Sie vergleichen sie mit einem Wert, den PostgreSQL als Typ text interpretiert hat.

SQLite hingegen ist "schwach typisiert" - Werte werden frei als derjenige Typ behandelt, der für die auszuführende Aktion am besten geeignet ist. In Ihrer dev SQLite-Datenbank kann die Operation '42' = 42 einfach berechnet werden, wobei PostgreSQL eine bestimmte Definition von VarChar = int (oder text = int, text ist der Typ für ungebundene Strings in PostgreSQL) benötigen würde.

Jetzt wird PostgreSQL manchmal hilfreich sein und automatisch Ihre Werte "umwandeln", damit die Typen mit einem bekannten Operator übereinstimmen, aber häufiger, wie der Hinweis sagt, müssen Sie dies explizit tun. Wenn Sie die SQL selbst schreiben, könnte ein expliziter Typfall wie WHERE id = CAST('42' AS INT) (oder WHERE CAST(id AS text) = '42') aussehen.

Da dies nicht der Fall ist, müssen Sie sicherstellen, dass die Eingabe, die Sie dem Abfragegenerator geben, eine tatsächliche Ganzzahl ist und nicht nur eine Zeichenfolge, die aus Ziffern besteht. Ich vermute, dies ist so einfach wie die Verwendung von fields.IntegerField anstelle von fields.CharField, aber ich kenne Django oder Python nicht wirklich, also dachte ich, ich würde Ihnen den Hintergrund geben, in der Hoffnung, dass Sie es von dort nehmen können.

32
IMSoP

Damit Sie nicht in ORM und externe Software-Postgres gehackt werden, können Sie Ihre eigenen Casts registrieren und Vorgänge vergleichen. Bitte schauen Sie sich Beispiel in ähnlicher Frage an .

0
Hubbitus