#16055: Filtering over generic relations with TextField/CharField object_id 
breaks
in postgres
--------------------------------------+------------------------------------
     Reporter:  anonymous             |                    Owner:  nobody
         Type:  Bug                   |                   Status:  new
    Component:  contrib.contenttypes  |                  Version:  1.3
     Severity:  Normal                |               Resolution:
     Keywords:                        |             Triage Stage:  Accepted
    Has patch:  0                     |      Needs documentation:  0
  Needs tests:  0                     |  Patch needs improvement:  0
Easy pickings:  0                     |                    UI/UX:  0
--------------------------------------+------------------------------------

Comment (by Nekmo):

 I have made a hack for Django-guardian. In my case, this query is the one
 that fails:


 {{{
 from customers.models import CustomerMemberObjectPermission

 
CustomerMemberObjectPermission.objects.filter(service_api__service__service_name='foo')
 # Raise DatabaseError
 }}}

 My models:

 {{{
 class CustomerMemberObjectPermission(UserObjectPermission):
     objects = CustomerMemberObjectPermissionManager()


 class ServiceApi(Model):
     customer_permissions = GenericRelation(CustomerMemberObjectPermission,
 object_id_field='object_pk',
 related_query_name='service_api')
 }}}

 This is the wrong sql:
 {{{
 SELECT "guardian_userobjectpermission"."id",
 "guardian_userobjectpermission"."permission_id",
 "guardian_userobjectpermission"."content_type_id",
 "guardian_userobjectpermission"."object_pk",
 "guardian_userobjectpermission"."user_id" FROM
 "guardian_userobjectpermission" INNER JOIN "services_serviceapi" ON
 ("guardian_userobjectpermission"."object_pk" = "services_serviceapi"."id"
 AND ("guardian_userobjectpermission"."content_type_id" = 22)) INNER JOIN
 "services_service" ON ("services_serviceapi"."service_id" =
 "services_service"."id") INNER JOIN "customers_customer" ON
 ("services_service"."customer_id" = "customers_customer"."id") WHERE
 "customers_customer"."customer_code" = BCL
 }}}

 The error is in the inner join. Django-guardian uses a field of type
 string for object_pk. But my id is a integer type:
 {{{
 "guardian_userobjectpermission"."object_pk" = "services_serviceapi"."id"
 }}}

 The solution is to use a cast:
 {{{
 CAST("guardian_userobjectpermission"."object_pk" AS integer) =
 "services_serviceapi"."id"
 }}}

 Although I know it is not the best, my solution has been this hack thanks
 to Simon Charette:
 {{{
 class CustomJoin(Join):
     def as_sql(self, compiler, connection):
         sql, params = super(CustomJoin, self).as_sql(compiler, connection)
         sql = sql.replace('"guardian_userobjectpermission"."object_pk"',
 'CAST("guardian_userobjectpermission"."object_pk" AS integer)')
         return sql, params


 class CustomSQLCompiler(SQLCompiler):
     def compile(self, node, select_format=False):
         if isinstance(node, Join):
             node = CustomJoin(
                 node.table_name, node.parent_alias, node.table_alias,
 node.join_type,
                 node.join_field, node.nullable, node.filtered_relation
             )
         return super(CustomSQLCompiler, self).compile(node, select_format)


 class CustomQuery(Query):
     def get_compiler(self, using=None, connection=None):
         original_compiler = super(CustomQuery,
 self).get_compiler(using=using, connection=connection)
         return CustomSQLCompiler(original_compiler.query,
 original_compiler.connection, original_compiler.using)
         # return super(CustomQuery, self).get_compiler(using=using,
 connection=connection)


 class CustomerMemberObjectPermissionQuerySet(CustomerQuerySet):
     def __init__(self, model=None, query=None, using=None, hints=None):
         if not query:
             query = CustomQuery(model)
         super(CustomerMemberObjectPermissionQuerySet, self).__init__(
             model=model, query=query, using=using, hints=hints
         )


 class CustomerMemberObjectPermissionManager(CustomerManager,
 UserObjectPermissionManager):
     def get_queryset(self):
         return CustomerMemberObjectPermissionQuerySet(self.model,
 using=self._db)
 }}}

-- 
Ticket URL: <https://code.djangoproject.com/ticket/16055#comment:12>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/067.40cc091896a93c381ca26cf22c8a759b%40djangoproject.com.

Reply via email to