heroku, postgreSQL, django, comments, tastypie: ни один оператор не соответствует заданному имени и типу аргументов. Возможно, Вам потребуется добавить явные приведения типов

у меня есть простой запрос на встроенную модель комментариев django и получение ошибки ниже с базой данных postgreSQL 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.

после googling вокруг кажется, что эта ошибка была решена много раз раньше в 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)

у кого-нибудь есть опыт обхода этой ошибки без написания raw SQL?

3 ответов


PostgreSQL "строго типизирован" - то есть каждое значение в каждом запросе имеет определенный тип, либо определенный явно (например, тип столбца в таблице), либо неявно (например, значения, введенные в WHERE предложения). Все функции и операторы, включая =, должны быть определены как принимающие определенные типы-так, например, есть оператор для VarChar = VarChar, а другой int = int.

в вашем случае, у вас есть столбец, который однозначно определяется как тип int, но вы сравниваете его со значением, которое PostgreSQL интерпретировал как type text.

SQLite, с другой стороны, является" слабо типизированным " - значения свободно рассматриваются как имеющие тот тип, который лучше всего подходит для выполняемого действия. Таким образом, в вашей базе данных dev 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, поэтому я подумал, что дам вам фон в надежде, что вы можете взять его оттуда.


основываясь на ответе IMSoP: это ограничение слоя ORM django, когда общий внешний ключ использует текстовое поле для object_id, а поле id объекта не является текстовым полем. Django не хочет делать никаких предположений или бросать идентификатор объекта как то, что это не так. Я нашел отличную статью об этом http://charlesleifer.com/blog/working-around-django-s-orm-to-do-interesting-things-with-gfks/.

автор статьи Чарльз Лейфер пришел с очень крутым решением для запросов, которые затронуты этим и будут очень полезны при решении этой проблемы.

кроме того, мне удалось заставить мой запрос работать следующим образом:

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, подобный тому, что сделал Чарльз, но оказалось, что все, что мне нужно было сделать, это разбить запрос на две части и преобразовать str (id) в int(id).


чтобы не взломать вас ORM и внешнее программное обеспечение postgres позволяют регистрировать свои собственные слепки и сравнивать операции. пожалуйста, посмотрите пример в аналогичном вопросе.