Set required custom field value to the default value if omitted #11000

Open
opened 2025-12-29 21:39:01 +01:00 by adam · 1 comment
Owner

Originally created by @atownson on GitHub (Apr 8, 2025).

NetBox version

v4.2.6

Feature type

Change to existing functionality

Proposed functionality

Currently API POST requests, bulk imports, and scripts that create instances of models require a value for all custom fields whose required field is True. It is possible to create a custom field with both required=True and a defined default value. This results in the UI forms pre-populating the custom fields with the default value, but has no effect with API requests, bulk imports, or scripts.
This feature request proposes to set the value of any required custom field to its default value when saving instances from the mechanisms listed and the custom field is omitted in the request. This would not apply to custom fields without a default value specified.

For example: If you had the required, Boolean custom field monitored defined for the Site model with a default value of false, you could:

  1. Send an POST API request with a body as such:
{"name": "My Site", "slug": "my-site"}
  1. Bulk import Sites as such:
name,slug,status
My Site,my-site,active
  1. Write a script as such:
...
site = Site(
    name = "My Site",
    slug = "my-site"
)
site.full_clean()
site.save()

and all would set monitored=false for the custom field payload.

Use case

This would simplify requests by not requiring a value if the default value is intended. It would allow the other, non-UI, mechanisms that create model instances to "pre-populate" the default values in a sense.

I think whether or not this request should be implemented comes down to terminology. If "required" means "the field should always have a value", then this request seems reasonable. If "required" means "a value is always required to be submitted", then this request should not be implemented.

Database changes

None

External dependencies

None

Originally created by @atownson on GitHub (Apr 8, 2025). ### NetBox version v4.2.6 ### Feature type Change to existing functionality ### Proposed functionality Currently API POST requests, bulk imports, and scripts that create instances of models require a value for all custom fields whose `required` field is `True`. It is possible to create a custom field with both `required=True` and a defined `default` value. This results in the UI forms pre-populating the custom fields with the default value, but has no effect with API requests, bulk imports, or scripts. This feature request proposes to set the value of any required custom field to its default value when saving instances from the mechanisms listed and the custom field is omitted in the request. This would not apply to custom fields without a default value specified. For example: If you had the required, Boolean custom field `monitored` defined for the Site model with a default value of `false`, you could: 1. Send an POST API request with a body as such: ``` {"name": "My Site", "slug": "my-site"} ``` 2. Bulk import Sites as such: ``` name,slug,status My Site,my-site,active ``` 3. Write a script as such: ``` ... site = Site( name = "My Site", slug = "my-site" ) site.full_clean() site.save() ``` and all would set `monitored=false` for the custom field payload. ### Use case This would simplify requests by not requiring a value if the default value is intended. It would allow the other, non-UI, mechanisms that create model instances to "pre-populate" the default values in a sense. I think whether or not this request should be implemented comes down to terminology. If "required" means "the field should always have a value", then this request seems reasonable. If "required" means "a value is always required to be submitted", then this request should not be implemented. ### Database changes None ### External dependencies None
adam added the type: featurenetboxstatus: backlogcomplexity: low labels 2025-12-29 21:39:01 +01:00
Author
Owner

@bctiemann commented on GitHub (Apr 9, 2025):

From the DRF docs:

required

Normally an error will be raised if a field is not supplied during deserialization. Set to false if this field is not required to be present during deserialization.

Setting this to False also allows the object attribute or dictionary key to be omitted from output when serializing the instance. If the key is not present it will simply not be included in the output representation.

Defaults to True. If you're using Model Serializer default value will be False if you have specified blank=True or default or null=True at your field in your Model.
...
Note that setting a default value implies that the field is not required. Including both the default and required keyword arguments is invalid and will raise an error.

The Django docs for forms:

By default, each Field class assumes the value is required, so if you pass an empty value – either None or the empty string ("") – then clean() will raise a ValidationError exception:

So the two contexts mean somewhat different things, in my reading. Django Forms will take a required=False field with an empty value and normalize it to None or '' or whatever is appropriate for the field type; but otherwise, because form payloads always include all specified fields, there is no such thing as an "omitted" field and a None or '' value will raise a validation error. But for DRF, required means "the key must be present in the payload or else a validation error will be raised". In either case It has no bearing on the default value, which is a model property rather than a form field or serializer field property and takes effect only if an object is instantiated without the field specified.

I don't think either of these behaviors maps perfectly onto the current custom fields behavior, where it is possible to set a field required but all that means is that in the UI, a form field is generated appropriate to the field type (in to_form_field) with required=True, thus taking on the Django Forms behavior rather than the DRF behavior.

So NetBox's handling of required in the API is neither fish nor fowl. And it seems to me that the current behavior (required is enforced in the model validate method and raises a ValidationError if the value is None or '', omitting the field is treated as None and raises an error in clean (I believe — please confirm), and default values are ignored) is surprising and out of step with what one would expect from a combination of DRF and model-level validation.

I would at first think DRF is the right model to follow here. required should mean "the key must be supplied", and specifying both required and default is invalid and should raise an error. But that would prevent the current UI behavior from working properly (a field might be required, but, contrary to Django forms' standard behavior, the default value is used to prepopulate the input).

So in the absence of a consistent way to handle this in both UI and API that follows either the Django or DRF convention, I think where I would land is that this is a good change and should be implemented for convenience. Note, however, that because custom fields can't use a callable as the default as in Django models, this could lead to many objects being created with the same value for a given custom field. This may be desirable behavior, but could be problematic if someone expects the value to be unique or derived in some way from the object's properties.

@bctiemann commented on GitHub (Apr 9, 2025): From the [DRF docs](https://www.django-rest-framework.org/api-guide/fields/#core-arguments): > required > >Normally an error will be raised if a field is not supplied during deserialization. Set to false if this field is not required to be present during deserialization. > >Setting this to False also allows the object attribute or dictionary key to be omitted from output when serializing the instance. If the key is not present it will simply not be included in the output representation. > >Defaults to True. If you're using [Model Serializer](https://www.django-rest-framework.org/api-guide/serializers/#modelserializer) default value will be False if you have specified blank=True or default or null=True at your field in your Model. > ... >Note that setting a default value implies that the field is not required. Including both the default and required keyword arguments is invalid and will raise an error. The [Django docs for forms](https://docs.djangoproject.com/en/5.1/ref/forms/fields/#required): >By default, each Field class assumes the value is required, so if you pass an empty value – either None or the empty string ("") – then clean() will raise a ValidationError exception: So the two contexts mean somewhat different things, in my reading. Django Forms will take a `required=False` field with an empty value and normalize it to `None` or `''` or whatever is appropriate for the field type; but otherwise, because form payloads always include all specified `fields`, there is no such thing as an "omitted" field and a `None` or `''` value will raise a validation error. But for DRF, `required` means "the key must be present in the payload or else a validation error will be raised". In either case It has no bearing on the `default` value, which is a model property rather than a form field or serializer field property and takes effect only if an object is instantiated without the field specified. I don't think either of these behaviors maps perfectly onto the current custom fields behavior, where it is possible to set a field `required` but all that means is that in the UI, a form field is generated appropriate to the field type (in `to_form_field`) with `required=True`, thus taking on the Django Forms behavior rather than the DRF behavior. So NetBox's handling of `required` in the API is neither fish nor fowl. And it seems to me that the current behavior (`required` is enforced in the model `validate` method and raises a ValidationError if the value is `None` or `''`, omitting the field is treated as `None` and raises an error in `clean` (I believe — please confirm), and default values are ignored) is surprising and out of step with what one would expect from a combination of DRF and model-level validation. I would at first think DRF is the right model to follow here. `required` should mean "the key must be supplied", and specifying both `required` and `default` is invalid and should raise an error. But that would prevent the current UI behavior from working properly (a field might be required, but, contrary to Django forms' standard behavior, the `default` value is used to prepopulate the input). So in the absence of a consistent way to handle this in both UI and API that follows either the Django or DRF convention, I think where I would land is that this is a good change and should be implemented for convenience. Note, however, that because custom fields can't use a callable as the default as in Django models, this could lead to many objects being created with the same value for a given custom field. This may be desirable behavior, but could be problematic if someone expects the value to be unique or derived in some way from the object's properties.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/netbox#11000