1

I'm working with raw SQL queries in a Django+PostgreSQL app, and I've come across the problem of having to pass as parameter a PostgreSQL Array value (of type tags = ArrayField(m.CharField(max_length=80) in app / tags character varying(80)[] in db).

I'm using code like this:

Product.objects.raw('SELECT * FROM myapp_code_products WHERE tags @> %s', [
    ['red'] # also tried with simply string '{"red"}' but that didn't work either, also tried with tuple
])

...in the hope of getting SQL like this generated:

SELECT * FROM myapp_code_products WHERE (tags @> '{"red"}')

but I either get simply nothing substituted like (tags @>) or list or tuple substitution like (tags @> ['red']) or (tags @> ('red')) and obviously none of this result in a valid contains query.

And, if anyone is wondering, the substituted parameter is user-supplied, so just completely bypassing parameter substitution here is not an option security-wise.

Note: also, using raw queries is to be considered a requirement here, using querysets and model queries is not an option here.

(Detail: I'm using Django 1.10.5 with Python 3.6.0 and PostgreSQL 9.3 on Windows 10 64bit)

1
  • So, you don't want to use ArrayField's contains lookup which builds @> queries for you, right? Commented Mar 7, 2017 at 15:57

1 Answer 1

1

Here is an example that works for me on postgres 9.6:

>>> from django.db import connection
>>> a = ["a","b","c"]
>>> b = ["b"]
>>> c = connection.cursor()
>>> c.execute("""SELECT %s::VARCHAR[] @> %s::VARCHAR[];""", (a,b))
>>> c.fetchall()
[(True,)]

Keep in mind that if tags is an ArrayField, this should work as well:

Product.objects.filter(tags__contains=['red'])
Sign up to request clarification or add additional context in comments.

2 Comments

thanks! this worked. what I tried before was array%s::varchar[] without realizing that array is added automatically when substituting a list as param value, so it ended up producing arrayARRAY[...]::varchar[]. I was just not paying attention
and if you could please edit you answer to also include a >>> c = connection.cursor() line to be 100% executable code :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.