Empty Image Fields in Django
tl;dr
Django FileFields and ImageFields are stored as strings in your database. Don't use null=True
with them, instead use blank=True
and filter by .filter(image__exact="")
.
Discovering a Bug
I ran into a bug where I was trying to filter a QuerySet by image__isnull=False
to determine if the image
field was set. It ended up returning all objects where image
was not yet set, so I did some digging.
How FileField
and ImageField
Look in the Database
The FileField
and ImageField
are both implemented in your database table as a varchar
field. Note the type column from the psql display table below:
Table "public.myapp_mymodel"
Column | Type | Collation | Nullable | Default
--------------+------------------------+-----------+----------+----------------------------------
id | bigint | | not null | generated by default as identity
image | character varying(100) | | not null |
This stores the relative path of the file, including your upload_to
and filename.
The problem is that these strings have two values that might mean "empty": None
and ""
.
How to Define a Model with Not Required File Fields
I had defined my model like this:
class MyModel(models.Model):
image = models.ImageField(
upload_to="images/",
null=True,
blank=True,
)
But I should have removed the null=True
option:
class MyModel(models.Model):
image = models.ImageField(
upload_to="images/",
blank=True,
)
How to Filter for Empty File Fields
Now, I still cannot filter by image__isnull
, because the image
field should never be set to NULL
in the database and None
in Python.
But I can filter by .filter(image__exact="")
, which is the empty string.
Or exclude those values with .exclude(image__exact="")
.