IPAddress.objects.get_or_create return .address as str when created=true #11651

Closed
opened 2025-12-29 21:48:06 +01:00 by adam · 2 comments
Owner

Originally created by @laherre on GitHub (Sep 25, 2025).

NetBox Edition

NetBox Community

NetBox Version

v4..4.1

Python Version

3.12

Steps to Reproduce

on CLI:

./manage.py nbshell

>>> ip_with_mask='192.168.1.240/24'
>>> ipam.IPAddress.objects.filter(address=ip_with_mask).count()
0
>>> ipa, created = ipam.IPAddress.objects.get_or_create(address=ip_with_mask)
>>> created
True
>>> type(ipa)
<class 'ipam.models.ip.IPAddress'>
>>> type(ipa.address)
<class 'str'>
>>> ipa, created = ipam.IPAddress.objects.get_or_create(address=ip_with_mask)
>>> created
False
>>> type(ipa)
<class 'ipam.models.ip.IPAddress'>
>>> type(ipa.address)
<class 'netaddr.ip.IPNetwork'>

It also works if call .refresh_from_db()

The same issue occurs when I create the object with IPAddress contructor:

ipa = ipam.IPAddress(address=ip_with_mask)
>>> type(ipa)
<class 'ipam.models.ip.IPAddress'>
>>> type(ipa.address)
<class 'str'>
>>> ipa.save()
>>> type(ipa.address)
<class 'str'>
>>> ipa.refresh_from_db()
>>> type(ipa.address)
<class 'netaddr.ip.IPNetwork'>

Expected Behavior

IPAddress.address must be 'netaddr.ip.IPNetwork' when created.

Observed Behavior

When IPAddress is created, the field .address is created as type str . The object must be reloaded from db .

Originally created by @laherre on GitHub (Sep 25, 2025). ### NetBox Edition NetBox Community ### NetBox Version v4..4.1 ### Python Version 3.12 ### Steps to Reproduce on CLI: ./manage.py nbshell ``` >>> ip_with_mask='192.168.1.240/24' >>> ipam.IPAddress.objects.filter(address=ip_with_mask).count() 0 >>> ipa, created = ipam.IPAddress.objects.get_or_create(address=ip_with_mask) >>> created True >>> type(ipa) <class 'ipam.models.ip.IPAddress'> >>> type(ipa.address) <class 'str'> >>> ipa, created = ipam.IPAddress.objects.get_or_create(address=ip_with_mask) >>> created False >>> type(ipa) <class 'ipam.models.ip.IPAddress'> >>> type(ipa.address) <class 'netaddr.ip.IPNetwork'> ``` It also works if call `.refresh_from_db()` The same issue occurs when I create the object with IPAddress contructor: ``` ipa = ipam.IPAddress(address=ip_with_mask) >>> type(ipa) <class 'ipam.models.ip.IPAddress'> >>> type(ipa.address) <class 'str'> >>> ipa.save() >>> type(ipa.address) <class 'str'> >>> ipa.refresh_from_db() >>> type(ipa.address) <class 'netaddr.ip.IPNetwork'> ``` ### Expected Behavior IPAddress.address must be 'netaddr.ip.IPNetwork' when created. ### Observed Behavior When IPAddress is created, the field _.address_ is created as type _str_ . The object must be reloaded from db .
adam added the netbox label 2025-12-29 21:48:06 +01:00
adam closed this issue 2025-12-29 21:48:07 +01:00
Author
Owner

@rfdrake commented on GitHub (Sep 25, 2025):

I don't think this is a bug. I think you're hitting the django thing where full_clean() is needed.

Take a look at this:

>>> ip_with_mask='192.168.1.242/24'
>>> ipa, created = ipam.IPAddress.objects.get_or_create(address=ip_with_mask)
>>> created
True
>>> ipa.full_clean()
>>> type(ipa.address)
<class 'netaddr.ip.IPNetwork'>
@rfdrake commented on GitHub (Sep 25, 2025): I don't think this is a bug. I think you're hitting the django thing where full_clean() is needed. Take a look at this: ``` >>> ip_with_mask='192.168.1.242/24' >>> ipa, created = ipam.IPAddress.objects.get_or_create(address=ip_with_mask) >>> created True >>> ipa.full_clean() >>> type(ipa.address) <class 'netaddr.ip.IPNetwork'> ```
Author
Owner

@laherre commented on GitHub (Sep 26, 2025):

Thanx for the info.

@laherre commented on GitHub (Sep 26, 2025): Thanx for the info.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/netbox#11651