heroku, postgreSQL, django, comments, tastypie: Ningún operador coincide con el nombre y tipo(s) de argumento. Es posible que necesite agregar conversiones de tipo explícito
django-comments (3)
Tengo una consulta simple en el modelo de comentarios integrado de django y obtengo el siguiente error con la base de datos postgreSQL de 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.
Después de buscar en Google, parece que este error se ha solucionado muchas veces antes en django, pero todavía lo estoy consiguiendo (todos los problemas relacionados se cerraron hace 3 a 5 años). Estoy usando la versión 1.4 de django y la última versión de tastypie.
La consulta se realiza bajo los filtros orm y funciona perfectamente con mi base de datos de desarrollo (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)
¿Alguien tiene experiencia en solucionar este error sin escribir SQL en bruto?
Para no piratearlo, los postgres ORM y de software externo le permiten registrar sus propios lanzamientos y comparar operaciones. Por favor mira el ejemplo en una pregunta similar .
PostgreSQL está "fuertemente tipado", es decir, cada valor en cada consulta tiene un tipo particular, ya sea definido explícitamente (por ejemplo, el tipo de una columna en una tabla) o implícitamente (por ejemplo, la entrada de valores en una cláusula WHERE
). Todas las funciones y operadores, incluido =
, deben definirse como aceptar tipos específicos, por lo que, por ejemplo, hay un operador para VarChar = VarChar
y uno diferente para int = int
.
En su caso, tiene una columna que se define explícitamente como tipo int
, pero la está comparando con un valor que PostgreSQL ha interpretado como text
tipo.
SQLite, por otro lado, está "tipificado débilmente": los valores se tratan libremente como si fueran del tipo que mejor se adapte a la acción que se está realizando. Por lo tanto, en su base de datos dev SQLite, la operación ''42'' = 42
puede calcularse bien, donde PostgreSQL necesitaría una definición específica de VarChar = int
(o text = int
, siendo el text
el tipo de cadenas ilimitadas en PostgreSQL).
Ahora, PostgreSQL a veces será útil y automáticamente "convertirá" sus valores para que los tipos coincidan con un operador conocido, pero más a menudo, como lo indica la sugerencia, debe hacerlo explícitamente. Si usted mismo estuviera escribiendo el SQL, un caso de tipo explícito podría verse como WHERE id = CAST(''42'' AS INT)
(o WHERE CAST(id AS text) = ''42''
).
Como no lo es, debe asegurarse de que la entrada que le da al generador de consultas sea un número entero real, no solo una cadena que consiste en dígitos. Sospecho que esto es tan simple como usar fields.IntegerField
fields.CharField
fields.IntegerField
lugar de fields.IntegerField
fields.CharField
fields.IntegerField
, pero en realidad no conozco a Django, ni a Python, así que pensé en darte el fondo con la esperanza de que puedas tomarlo desde allí.
Sobre la base de la respuesta de IMSoP: esta es una limitación de la capa ORM de django cuando una clave externa genérica utiliza un campo de texto para el ID de objeto y el campo de identificación del objeto no es un campo de texto. Django no quiere hacer suposiciones o convertir la identificación del objeto como algo que no es. Encontré un excelente artículo en este http://charlesleifer.com/blog/working-around-django-s-orm-to-do-interesting-things-with-gfks/ .
El autor del artículo, Charles Leifer, ideó una solución muy buena para consultas que se ven afectadas por esto y será muy útil para tratar este problema en el futuro.
Alternativamente, logré que mi consulta funcionara de la siguiente manera:
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
Originalmente estaba buscando una manera de modificar el SQL similar a lo que Charles ha hecho, pero resulta que todo lo que tenía que hacer era dividir la consulta en dos partes y convertir las str (id) a int (id) '' s.