Invalid query when combining with ArrayField and NULL values
When combining a field from this library with ArrayField if any of the values in the array is None (or should be translated to NULL) an invalid query is generated causing an error like the following:
django.db.utils.DataError: invalid input syntax for type ...
In example, if using InetAddressField the generated SQL is something like
SELECT '{192.168.1.1,None}'::inet[]::inet[];
Using django built-in GenericIPAddressField instead produces the right query:
SELECT '{192.168.1.1,NULL}'::inet[]::inet[];
Here is a sample model with tests to ensure this behaviour:
# models.py
from django.contrib.postgres.fields import ArrayField
from django.db import models
from netfields import (CidrAddressField, InetAddressField, MACAddress8Field,
MACAddressField)
class ArrayModel(models.Model):
ip_array = ArrayField(models.GenericIPAddressField(), null=True)
inet_array = ArrayField(InetAddressField(), null=True)
mac_array = ArrayField(MACAddressField(), null=True)
mac8_array = ArrayField(MACAddress8Field(), null=True)
cidr_array = ArrayField(CidrAddressField(), null=True)
# tests.py
from django.test import TestCase
from .models import ArrayModel
class NullsTestCase(TestCase):
def test_ip(self):
model = ArrayModel(ip_array=["192.168.1.1", None])
model.save()
def test_inet(self):
model = ArrayModel(inet_array=["192.168.1.1", None])
model.save()
def test_mac(self):
model = ArrayModel(mac_array=["FF:FF:FF:FF:FF:FF", None])
model.save()
def test_mac8(self):
model = ArrayModel(mac8_array=["FF:FF:FF:FF:FF:FF", None])
model.save()
def test_cidr(self):
model = ArrayModel(cidr_array=["192.168.1.0/24", None])
model.save()
I have seen this issue using Django 4.2 and psycopg 3.1.17.
Looking into django code I see that GenericIPAddressField.get_db_prep_value internally calls connection.ops.adapt_ipaddressfield_value which behaves different from netfields:
https://github.com/django/django/blob/c7e986fc9f4848bd757d4b9b70a40586d2cee9fb/django/db/backends/postgresql/operations.py#L350-L353
Because if the value is falsy it just returns None and not Inet(None) (which is the result in netfields).