Opened 5 years ago

Closed 5 years ago

Last modified 5 years ago

#30788 closed Bug (duplicate)

Fix concatenation of tuple to list (or vice versa)

Reported by: Dmitry Mugtasimov Owned by: nobody
Component: Database layer (models, ORM) Version: dev
Severity: Normal Keywords: postgresql
Cc: Massimo Costa Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

Sometimes you may get

TypeError: can only concatenate tuple (not "list") to tuple

As you see it happens because lhs_params is tuple and rhs_params is list.

    def as_sql(self, qn, connection):
        lhs, lhs_params = self.process_lhs(qn, connection)
        rhs, rhs_params = self.process_rhs(qn, connection)
>       params = lhs_params + rhs_params
E       TypeError: can only concatenate tuple (not "list") to tuple

connection = <django.db.backends.postgresql.base.DatabaseWrapper object at 0x7f4845880b38>
lhs        = '(SELECT ARRAY_AGG(U0."experience_id" ) AS "experience_levels" FROM "jobs_jobtitleexperiencetrough" U0 WHERE U0."title_id" = ANY(("jobs_job"."titles")))'
lhs_params = ()
qn         = <django.db.models.sql.compiler.SQLCompiler object at 0x7f483d658860>
rhs        = '%s'
rhs_params = [(21,)]
self       = <django.contrib.postgres.fields.array.ArrayContains object at 0x7f483d67a0f0>

This is because of implementation of PostgresSimpleLookup:

class PostgresSimpleLookup(Lookup):
    def as_sql(self, qn, connection):
        lhs, lhs_params = self.process_lhs(qn, connection)
        rhs, rhs_params = self.process_rhs(qn, connection)
        params = lhs_params + rhs_params
        return '%s %s %s' % (lhs, self.operator, rhs), params

I use this workaround:

class FixedArrayContains(DataContains):
    def super_as_sql(self, qn, connection):
        lhs, lhs_params = self.process_lhs(qn, connection)
        rhs, rhs_params = self.process_rhs(qn, connection)
        params = list(lhs_params) + list(rhs_params)
        return '%s %s %s' % (lhs, self.operator, rhs), params

    def as_sql(self, qn, connection):
        sql, params = self.super_as_sql(qn, connection)
        sql = '%s::%s' % (sql, self.lhs.output_field.db_type(connection))
        return sql, params

Please, provide a solution

Change History (6)

comment:1 by Mariusz Felisiak, 5 years ago

Resolution: needsinfo
Status: newclosed
Version: 2.2master

Thanks for the report, however I cannot reproduce this issue on bae05bcf68710cb6dafa51325c3ec83ddda83c39. Can you provide models and a queryset?

comment:2 by Massimo Costa, 5 years ago

Resolution: needsinfo
Status: closednew

I can confirm this is a BUG introduced in v2.2.6 most likely in https://code.djangoproject.com/ticket/30769

In my case was about a QuerySet with a filter on a JSONField
Here my model

class CustomFieldDefinition(models.Model):
    """
    Custom field
    """

    ....

    metadata = JSONField(
        verbose_name="Additional information relative to the field.",
        default=dict,
    )

and this is my queryset

    qs = CustomFieldDefinition.objects.filter(pk__in=values) \
        .filter(metadata__LDAP__has_key='attributename') \
        .values_list('metadata', flat=True)

the metadata field stores a JSON object with a LDAP nested Object

{
   "LDAP": {
        ...
   }
}

as soon as I run

qs.all()

I get the same error

in v2.2.5 the code works

Last edited 5 years ago by Massimo Costa (previous) (diff)

comment:3 by Massimo Costa, 5 years ago

Cc: Massimo Costa added

comment:4 by Simon Charette, 5 years ago

Resolution: fixed
Status: newclosed

Please provide the full traceback of the exception you are encountering. It's almost impossible to trace down without it.

comment:6 by Claude Paroz, 5 years ago

Resolution: fixedduplicate

Looks like a duplicate of #30826. Letting this one closed because the other has the regression test attached.
Thanks for reporting!

Note: See TracTickets for help on using tickets.
Back to Top