2013-04-16 8 views
14

Mam proste kwerendy w Django zbudowanych w komentarzach modelu i uzyskiwanie błąd poniżej z bazy danych PostgreSQL Heroku za:heroku, postgreSQL, django, komentarze, tastypie: Żaden operator nie pasuje do podanej nazwy i typu argumentu. Być może trzeba dodać wyraźny typ rzuca

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. 

Po googling wokół wydaje się ten błąd został rozwiązany wiele razy wcześniej w django, ale wciąż go otrzymuję (wszystkie powiązane kwestie zostały zamknięte 3-5 lat temu). Używam wersji 1.4 django i najnowszej wersji programu tastypie.

Zapytanie jest wykonany pod filtrami ORM i doskonale współpracuje z moim bazy rozwojowej (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) 

ktoś ma jakieś doświadczenia z poruszania się tego błędu bez pisania surowego SQL?

+0

Podobnie jak w przypadku błędu, próbujesz porównać liczbę całkowitą z wartością tekstową. Przestań to robić, a błąd zniknie. –

+0

Nawiasem mówiąc, jest to dobry przykład, dlaczego testowanie powinno odbywać się w środowisku możliwie najbardziej podobnym do miejsca, w którym się wdrażasz: niezależnie od tego, jak wiele frameworka twierdzi, że to abstrakcja, coś tak złożonego, jak DBMS, z pewnością będzie miało inne zachowanie i ograniczenia . – IMSoP

+0

IMSoP, tak naprawdę dzisiaj nauczyłem się tej lekcji! Właśnie zmieniłem DB mojego rozwoju do PostgreSQL, aby pracować nad tym problemem. – arctelix

Odpowiedz

4

Opierając się na odpowiedzi IMSoP: Jest to ograniczenie warstwy ORM django, gdy klucz ogólny Generic używa pola tekstowego dla id_obiektu, a pole id obiektu nie jest polem tekstowym. Django nie chce przyjmować żadnych założeń ani rzutować identyfikatora obiektu jako czegoś, czym nie jest. Znalazłem świetny artykuł na temat tego http://charlesleifer.com/blog/working-around-django-s-orm-to-do-interesting-things-with-gfks/.

Autor artykułu, Charles Leifer, wymyślił bardzo fajne rozwiązanie dla zapytania, na które ma wpływ ten komunikat i będzie bardzo przydatne w rozwiązywaniu tego problemu.

Alternatywnie, udało mi się dostać moje zapytanie do pracy w następujący sposób:

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 

Początkowo szukałem sposobu modyfikacji SQL podobny do tego, co Karol zrobił, ale okazuje się, wszystko, co musiałem to było podzielenie zapytania na dwie części i przekonwertowanie wartości str (id) na int (id).

29

PostgreSQL jest "silnie typowany" - to znaczy każda wartość w każdym zapytaniu ma określony typ, zdefiniowany jawnie (np. Typ kolumny w tabeli) lub niejawnie (np. Wartości wprowadzone do klauzuli WHERE) . Wszystkie funkcje i operatory, w tym =, muszą być zdefiniowane jako akceptujące określone typy - na przykład istnieje operator dla VarChar = VarChar, a inny dla .

W twoim przypadku masz kolumnę, która jest jawnie zdefiniowana jako typ int, ale porównujesz ją z wartością, którą PostgreSQL zinterpretował jako typ text.

Z kolei SQLite jest "słabo napisane" - wartości są dowolnie traktowane jako takie, które najlepiej pasują do wykonywanego działania. Tak więc w bazie danych SQLite można łatwo obliczyć operację '42' = 42, gdzie PostgreSQL potrzebowałby specyficznej definicji VarChar = int (lub text = int, text, która jest typem dla nieograniczonych ciągów w PostgreSQL).

Teraz PostgreSQL będzie czasami być pomocne i automatycznie "rzucić" swoje wartości, aby typy pasowały do ​​znanego operatora, ale częściej, jak podpowiedź mówi, musisz zrobić to jawnie. Jeśli pisałeś sam SQL, jawny typ może wyglądać tak: WHERE id = CAST('42' AS INT) (lub WHERE CAST(id AS text) = '42').

Ponieważ nie jest, należy upewnić się, że dane wejściowe przekazywane do generatora zapytań są rzeczywistą liczbą całkowitą, a nie tylko ciągiem składającym się z cyfr. Podejrzewam, że jest to tak proste, jak używanie fields.IntegerField, a nie fields.CharField, ale tak naprawdę nie znam Django, ani nawet Pythona, więc pomyślałem, że dam ci tło w nadziei, że możesz je tam zabrać.

+0

Dzięki za informacje, bardzo dobrze i rozumiem, co jest przyczyną błędu. Problem polega na tym, że gjk django dla modelu komentarzy używa pola tekstowego dla id_obiektu, a komentowany obiekt używa pola z liczbą całkowitą. Tak naprawdę zadaniem powinno być jak obejść to bez ograniczania modelu komentarza do liczby całkowitej id's. – arctelix

Powiązane problemy