Django PostgreSQL Netfields
django-netfields provides robust PostgreSQL net-related fields for Django models, specifically `INET`, `CIDR`, `MACADDR`, and `MACADDR8` types. It addresses limitations of Django's built-in IP address fields by providing efficient database-native lookups and supporting IPv6. The library is actively maintained, with the current version being 1.4.1, and typically follows Django's release cycle for compatibility updates.
Common errors
-
AttributeError: 'str' object has no attribute 'cidr' or TypeError: unexpected type <type 'list'> for addr arg
cause Attempting to use string representations for network fields (e.g., '192.168.1.0/24') directly with ORM methods like `get_or_create` or assignments, without converting them to `ipaddress.IPAddress` or `ipaddress.IPNetwork` objects first.fixAlways convert string representations of IP addresses or networks to appropriate `ipaddress` module objects (e.g., `ipaddress.ip_address('192.168.1.1')` or `ipaddress.ip_network('192.168.1.0/24')`) before passing them to `django-netfields` model fields or query methods. -
DatabaseError: operator does not exist: inet = text (or similar PostgreSQL casting error)
cause Trying to perform complex IP operations or lookups using Django's default `IPAddressField` or `GenericIPAddressField` against PostgreSQL `INET` or `CIDR` columns, which incorrectly casts `inet` types to `text`.fixMigrate your model fields from Django's default `IPAddressField` or `GenericIPAddressField` to `django-netfields`' `InetAddressField` or `CidrAddressField` to leverage PostgreSQL's native `inet` and `cidr` types and their operators. -
django.core.exceptions.AppRegistryNotReady: Apps aren't loaded yet.
cause Attempting to import `netfields` models or use `NetManager` before Django's application registry is fully set up, typically in standalone scripts without `django.setup()` or if 'netfields' is not in `INSTALLED_APPS`.fixEnsure 'netfields' is added to your project's `INSTALLED_APPS` in `settings.py`. For standalone scripts, ensure `django.setup()` is called after configuring minimal settings, and `makemigrations` and `migrate` are run.
Warnings
- gotcha For `InetAddressField` and `CidrAddressField`, you *must* use `NetManager` (e.g., `objects = NetManager()`) on your model to enable the advanced network-specific lookups like `__net_contained` or `__net_contains`.
- breaking Version 1.0.0 introduced significant changes to `django-rest-framework` fields provided by `django-netfields`. Code relying on string representations for validation or pre-save logic on unsaved models might require adjustments.
- gotcha By default, `InetAddressField` in Python represents values as `ipaddress.ip_interface` objects. If you only want an `ipaddress.ip_address` object (without the prefix length), you must set `store_prefix_length=False` when defining the field.
Install
-
pip install django-netfields
Imports
- InetAddressField
from netfields import InetAddressField
- CidrAddressField
from netfields import CidrAddressField
- MACAddressField
from netfields import MACAddressField
- MACAddress8Field
from netfields import MACAddress8Field
- NetManager
objects = models.Manager()
from netfields import NetManager
Quickstart
import os
import django
from django.conf import settings
from django.db import models
from netfields import InetAddressField, CidrAddressField, MACAddressField, NetManager
import ipaddress
import netaddr
# Minimal Django setup for standalone script
if not settings.configured:
settings.configure(
INSTALLED_APPS=['netfields'],
DATABASES={'default': {'ENGINE': 'django.db.backends.sqlite3', 'NAME': ':memory:'}},
DEBUG=True
)
django.setup()
class NetworkDevice(models.Model):
name = models.CharField(max_length=100)
ip_address = InetAddressField(unique=True)
network = CidrAddressField(blank=True, null=True)
mac_address = MACAddressField(blank=True, null=True)
objects = NetManager()
def __str__(self):
return f"{self.name} - {self.ip_address}"
# Create database schema (in-memory for example)
with django.test.utils.override_settings(MIGRATION_MODULES={'netfields': None}):
from django.core.management import call_command
call_command('makemigrations', 'netfields', interactive=False, verbosity=0)
call_command('migrate', interactive=False, verbosity=0)
# Usage examples
# Create instances with ipaddress/netaddr objects
device1 = NetworkDevice.objects.create(
name='Router1',
ip_address=ipaddress.ip_interface('192.168.1.1/24'),
network=ipaddress.ip_network('192.168.1.0/24'),
mac_address=netaddr.EUI('00:11:22:AA:BB:CC')
)
device2 = NetworkDevice.objects.create(
name='Server1',
ip_address=ipaddress.ip_address('192.168.1.100'),
network=ipaddress.ip_network('192.168.1.0/24')
)
# Retrieve and query
print(f"Device 1: {device1}")
print(f"Device 2: {device2}")
# Lookup using NetManager's custom lookups
# Find devices within a network
subnet_devices = NetworkDevice.objects.filter(ip_address__net_contained_or_equal='192.168.1.0/24')
print(f"\nDevices in 192.168.1.0/24: {list(subnet_devices)}")
# Find networks that contain a specific IP
containing_networks = NetworkDevice.objects.filter(network__net_contains='192.168.1.50')
print(f"Networks containing 192.168.1.50: {list(containing_networks)}")
# Update an instance
device1.ip_address = ipaddress.ip_interface('10.0.0.1/8')
device1.save()
print(f"Updated Device 1 IP: {device1.ip_address}")