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="").