Search code examples
djangodjango-modelsfilteringdjango-queryset

Django cannot cast type integer to smallint when attempting to filter a queryset


I have an IntegerChoices Genre:

from django.db import models
# ...

class Genre(models.IntegerChoices):
    fantasy = 0,
    scifi = 1,
    real = 2,
    #...

and a book model that uses an ArrayField of PositiveSmallIntegerField with Genre as choices:

from django.contrib.postgre.fields import ArrayField
#...

class Book(models.Model):
    #...
    genres = ArrayField(models.PositiveSmallIntegerField(choices=Genre.choices), null=True, blank=True))
    #...

When I try to filter by the genres field using values from the Genre choices I get an error that Django (or psycopg2) cannot cast an integer to a smallint:

# traceback
psycopg2.errors.CannotCoerce: cannot cast type integer to smallint[]
LINE 1: ..."book" WHERE "book"."genres" @> 1::smallint...
                                            ^

The above exception was the direct cause of the following exception:
# traceback
django.db.utils.ProgrammingError: cannot cast type integer to smallint[]
LINE 1: ..."book" WHERE "book"."genres" @> 1::smallint...
                                            ^

All of these attempts to filter trigger the above error:

genre = Genre.scifi
print(genre) # >>> 1
Book.objects.filter(genres__contains=genre) # error
Book.objects.filter(genres=genre) # error

However if I try to create a book instance with the genre everything works.

book = Book.objects.create(
    #...
    genres=[genre]
) # no error
print(book.genres) # >>> [1]

Is the problem the PositiveSmallIntegerField? I couldn't find any "SmallIntegerChoices" as a replacement for the IntegerChoices.
Or is it the way the filtering is/should be done? I haven't had this issue before and by searching I haven't found anything that looks the same (some errors with migrations or other type casting, but nothing quite like this).
It does feel like a simple problem, but I can't find my way around it.


Solution

  • When you are querying the ArrayField, you need to provide an array of value(s), you can not simply pass the value itself, so in this case, the variable 'genre' you are passing should be an array of value like, [1] or [1, 2, 3] for multiple values. It should fix your problem.

    Documentation of Querying in ArrayField for reference.