Repository: netbox-community/netbox

Issue:
Surrounding quotes of JSON custom field's simple string default value lost when editing device
### Deployment Type

Self-hosted

### NetBox Version

v3.7.6

### Python Version

3.11

### Steps to Reproduce

- Add a custom field of type JSON (extras/custom-fields/add/)
In the form use **DCIM > Device** as Content types, **testing** as name, **JSON** as type and **"testing"** (with the double quotes) as default value. Leave all the rest as it is and click create.
- Navigate to a device page.
- Click to edit the device.
- Try to save without changing anything. An Error **Enter a valid JSON** will show up (the surrounding quotes of the JSON custom fields values are lost, you can't save unless adding the quotes around the value **testing** in the JSON custom fields)

### Expected Behavior

When editing a device, surrounding quotes of JSON custom field values should be kept.

### Observed Behavior

Surrounding quotes of already defined JSON custom field values are lost when editing a device.


Discussion:
Thank you for opening a bug report. I was unable to reproduce the reported behavior on NetBox v3.7.6 in my lab. Please re-confirm the reported behavior 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. The demo system's database has been through a lot and may be a factor in what you're experiencing, which is why the [bug report template](https://github.com/netbox-community/netbox/issues/new?assignees=&labels=type%3A+bug%2Cstatus%3A+needs+triage&projects=&template=bug_report.yaml) explicitly states that the demo system should not be relied on when reporting bugs.
Hi, and thank you for your quick response. I've just updated the steps to reproduce the error. Forget about the demo instance then; I thought it would be easier since we both have access to it—sorry about that. The bug actually appeared recently; it was not present in version 3.5.X. Can you reproduce the bug now?
Okay, the clarified steps got me there, thanks.

This problem seems to happen only when the field's default value is exactly a quoted string. If the default value is a list or associative array, the problem does not occur for me in 3.7.6.

I'm updating the summary and moving to `needs owner`.

Resolving patch:
diff --git a/netbox/extras/models/customfields.py b/netbox/extras/models/customfields.py
--- a/netbox/extras/models/customfields.py
+++ b/netbox/extras/models/customfields.py
@@ -1,4 +1,5 @@
 import decimal
+import json
 import re
 from datetime import datetime, date
 
@@ -484,7 +485,7 @@ def to_form_field(self, set_initial=True, enforce_required=True, enforce_visibil
 
         # JSON
         elif self.type == CustomFieldTypeChoices.TYPE_JSON:
-            field = JSONField(required=required, initial=initial)
+            field = JSONField(required=required, initial=json.dumps(initial) if initial else '')
 
         # Object
         elif self.type == CustomFieldTypeChoices.TYPE_OBJECT:
diff --git a/netbox/netbox/forms/base.py b/netbox/netbox/forms/base.py
--- a/netbox/netbox/forms/base.py
+++ b/netbox/netbox/forms/base.py
@@ -1,3 +1,5 @@
+import json
+
 from django import forms
 from django.contrib.contenttypes.models import ContentType
 from django.db.models import Q
@@ -34,7 +36,11 @@ def _get_content_type(self):
     def _get_form_field(self, customfield):
         if self.instance.pk:
             form_field = customfield.to_form_field(set_initial=False)
-            form_field.initial = self.instance.custom_field_data.get(customfield.name, None)
+            initial = self.instance.custom_field_data.get(customfield.name)
+            if customfield.type == CustomFieldTypeChoices.TYPE_JSON:
+                form_field.initial = json.dumps(initial)
+            else:
+                form_field.initial = initial
             return form_field
 
         return customfield.to_form_field()


Test patch: