Repository: netbox-community/netbox

Issue:
Changes are not reflected correctly when deleting a primary ip for a device
### Deployment Type

Self-hosted

### NetBox Version

v3.5.7

### Python Version

3.8

### Steps to Reproduce

1. create a device with and an interface on device
2. create an IP-address and associate it to interface and make it primary ip
3. delete the IP-address

When deleting the IP-address changelog gets two entries, first one as update on device and then delete of IP-address

### Expected Behavior

The device update should have following:
pre-change - original device data
post-change - the device data with null as primary_ip 


### Observed Behavior

The device update gets following:
pre-change - "Warning: Comparing non-atomic change to previous change record"
post-change - the device data, and it also has an IP-address id as primary_ip

Same behavior is seen in webhooks


Discussion:
Thank you for opening a bug report. I was unable to reproduce the reported behavior on NetBox v3.6.6. Please re-confirm the reported behavior on the current stable release and adjust your post above as necessary. Remember to provide detailed steps that someone else can follow using a clean installation of NetBox to reproduce the issue. Remember to include the steps taken to create any initial objects or other data.
I have now tested the same on Netbox DEMO page with same behavior. I hope this gives you a better view of the issue.

Preparation:
1. create a device role named A
2. create a device type named A
3. create a device named A with device role A and device type A
4. create an interface on device named eth
5. create an IP-address named 1.2.3.4/24 and assign to device A interface eth, check the checkbox to make it primary

Now when deleting the IP-address we get two change logs.
1. Update on device A
2. Delete of IP-address 1.2.3.4/24
The change log on device never shows the update of primary IP

Below is from Netbox Demo page
![image](https://github.com/netbox-community/netbox/assets/28634241/4e539b86-f275-4b55-b2aa-df427ed4aeb5)
![image](https://github.com/netbox-community/netbox/assets/28634241/9ccc9630-4a90-450f-aaa7-aec4c063bd9d)
![image](https://github.com/netbox-community/netbox/assets/28634241/2c293639-1bf2-40bb-a19a-05d1a54bc4ad)


Resolving patch:
diff --git a/netbox/ipam/signals.py b/netbox/ipam/signals.py
--- a/netbox/ipam/signals.py
+++ b/netbox/ipam/signals.py
@@ -56,8 +56,12 @@ def clear_primary_ip(instance, **kwargs):
     """
     field_name = f'primary_ip{instance.family}'
     if device := Device.objects.filter(**{field_name: instance}).first():
+        device.snapshot()
+        setattr(device, field_name, None)
         device.save()
     if virtualmachine := VirtualMachine.objects.filter(**{field_name: instance}).first():
+        virtualmachine.snapshot()
+        setattr(virtualmachine, field_name, None)
         virtualmachine.save()
 
 
@@ -67,4 +71,6 @@ def clear_oob_ip(instance, **kwargs):
     When an IPAddress is deleted, trigger save() on any Devices for which it was a OOB IP.
     """
     if device := Device.objects.filter(oob_ip=instance).first():
+        device.snapshot()
+        device.oob_ip = None
         device.save()


Test patch: