Calculated Jinja2 based CustomFields #7620

Closed
opened 2025-12-29 20:26:06 +01:00 by adam · 6 comments
Owner

Originally created by @PieterL75 on GitHub (Feb 8, 2023).

NetBox version

v3.4.4

Feature type

New functionality

Proposed functionality

Create a custom field of the type 'Calculated'
This custom field is composed of a Jinja2 template that gives the ability to format the data of the object to an custom presentation.
It should provide the ability to represent create a string, a badge, a %graph, markdown, ...

Use case

There is a lot of a data in one model (device), and most of can be shown in a table column.
This custom field will create a way to merge multiple columns into one, or create a column with data that is not visible in the GUI (ex: number of interfaces)
https://github.com/netbox-community/netbox/issues/6347 will give even more fields to merge into a custom view

It will create the ability to provide fully customizable view, with the need to update the core of the code.

Database changes

No response

External dependencies

No response

Originally created by @PieterL75 on GitHub (Feb 8, 2023). ### NetBox version v3.4.4 ### Feature type New functionality ### Proposed functionality Create a custom field of the type 'Calculated' This custom field is composed of a Jinja2 template that gives the ability to format the data of the object to an custom presentation. It should provide the ability to represent create a string, a badge, a %graph, markdown, ... ### Use case There is a lot of a data in one model (device), and most of can be shown in a table column. This custom field will create a way to merge multiple columns into one, or create a column with data that is not visible in the GUI (ex: number of interfaces) https://github.com/netbox-community/netbox/issues/6347 will give even more fields to merge into a custom view It will create the ability to provide fully customizable view, with the need to update the core of the code. ### Database changes _No response_ ### External dependencies _No response_
adam added the type: featurestatus: under review labels 2025-12-29 20:26:06 +01:00
adam closed this issue 2025-12-29 20:26:07 +01:00
Author
Owner

@jeremystretch commented on GitHub (Feb 8, 2023):

IMO this wouldn't be an appropriate use of custom fields, as it's a pretty stark violation of the separation between data and presentation. Custom fields exist specifically to hold additional data about an object, not to to display existing data in an alternative format. I can appreciate the underlying use case, but I don't think custom fields are the right solution for it.

Edit to add: It seems like your focus is primarily on table columns. Maybe what you're really after is a way to inject custom columns?

@jeremystretch commented on GitHub (Feb 8, 2023): IMO this wouldn't be an appropriate use of custom fields, as it's a pretty stark violation of the separation between data and presentation. Custom fields exist specifically to hold additional data about an object, not to to display existing data in an alternative format. I can appreciate the underlying use case, but I don't think custom fields are the right solution for it. Edit to add: It seems like your focus is primarily on table columns. Maybe what you're really after is a way to inject custom columns?
Author
Owner

@PieterL75 commented on GitHub (Feb 8, 2023):

My proposal is mainly for columns, but I can imagine that it is also useful in the Deviceview or even in API results (not the badges, but the numbers)

I suppose you can see better solution than a custom field (your (net)box is bigger than my (net)box), but in my little box, that seemed a good idea :-)

@PieterL75 commented on GitHub (Feb 8, 2023): My proposal is mainly for columns, but I can imagine that it is also useful in the Deviceview or even in API results (not the badges, but the numbers) I suppose you can see better solution than a custom field (your (net)box is bigger than my (net)box), but in my little box, that seemed a good idea :-)
Author
Owner

@ryanmerolle commented on GitHub (Feb 10, 2023):

Relates to #8217

Other DCIM tools offer jinja custom_fields, and so this will likely come up from time to time.

If you are using custom fields for links to other tools like I was, I migrated to custom_links which allow for Jinja logic in the link text and url. It solved most of my use case.

My only other use case was for generating interface descriptions since I throw in circuit info and peer device/interface info into descriptions. I just achieve that by including the jinja logic in my config templates.

@ryanmerolle commented on GitHub (Feb 10, 2023): Relates to #8217 Other DCIM tools offer jinja custom_fields, and so this will likely come up from time to time. If you are using custom fields for links to other tools like I was, I migrated to custom_links which allow for Jinja logic in the link text and url. It solved most of my use case. My only other use case was for generating interface descriptions since I throw in circuit info and peer device/interface info into descriptions. I just achieve that by including the jinja logic in my config templates.
Author
Owner

@jeremystretch commented on GitHub (Feb 11, 2023):

I'll elaborate on my explanation above.

This custom field is composed of a Jinja2 template that gives the ability to format the data of the object to an custom presentation.

My understanding of the intent here is to expose as an object attribute some value that is rendered (or "computed") from one or more other attributes of that object. As a very contrived example, let's say we want to include a field in the REST API representation of a site that concatenates the name of its region with its own name. Suppose we want to do this using a simple Jinja2 filter:

{{ site.name }}, {{ site.region.name }}

So for example, a site named "Raleigh" in a region named "North Carolina" would look like this:

{
    "name": "Raleigh",
    "region": {
        "name": "North Carolina"
    },
    "custom-attributes": {
        "region-and-name": "Raleigh, North Carolina"
    }
}

There are two reasons we wouldn't want to use a custom field for this:

  1. The value of the custom attribute is dictated by some external piece of logic, outside the control the consumer.
  2. The custom attribute itself cannot be directly modified.

For example, there should never be an instance where an API consumer would need to set the value of the region-and-name attribute` directly: Instead, it's influenced by the values of the fields it references. Custom field values by contrast are mutable and can be set directly by an API consumer.

One key implication of this distinction is that computed attributes do not need to be stored per instance; we only need to define a per-model definition, which can be replicated for each instance. In this example, we just create a single attribute object tying our Jinja2 code to the site model. This allows us to render the attribute for every site.

The only reason I can see to store the computed value for each instance would be as a performance optimization (essentially caching the rendered output). But considering the overhead associated with keeping these values up to date combined with the additional complexity of supporting read-only custom fields, this seems unlikely to be worthwhile except in very complex scenarios.

Beyond the technical implementation, we must also consider the practical use case for such attributes: Given that APIs are intended to be consumed programmatically, what practical use cases can we identify that cannot be satisfied with the data already being provided. (As in the above example, the region and site names are already provided, and the client could render the custom attribute value independently.) Further, we would generally want to stop short of rendering any particular markup (e.g. HTML) as it could severely limit the practical application of the data being provided.

There is a lot of a data in one model (device), and most of can be shown in a table column.

Again, it feels like the intended use case here is specifically for the user interface, which is a valid consideration as it cannot be consumed programmatically. If anything, I would propose that the preferred implementation would be some mechanism by which custom attributes can be registered at the model level, and potentially conveyed as table columns and other elements in the user interface.

@jeremystretch commented on GitHub (Feb 11, 2023): I'll elaborate on my explanation above. > This custom field is composed of a Jinja2 template that gives the ability to format the data of the object to an custom presentation. My understanding of the intent here is to expose as an object attribute some value that is rendered (or "computed") from one or more _other_ attributes of that object. As a very contrived example, let's say we want to include a field in the REST API representation of a site that concatenates the name of its region with its own name. Suppose we want to do this using a simple Jinja2 filter: ``` {{ site.name }}, {{ site.region.name }} ``` So for example, a site named "Raleigh" in a region named "North Carolina" would look like this: ``` { "name": "Raleigh", "region": { "name": "North Carolina" }, "custom-attributes": { "region-and-name": "Raleigh, North Carolina" } } ``` There are two reasons we wouldn't want to use a custom field for this: 1. The value of the custom attribute is dictated by some external piece of logic, outside the control the consumer. 2. The custom attribute itself cannot be directly modified. For example, there should never be an instance where an API consumer would need to *set* the value of the `region-and-name` attribute` directly: Instead, it's influenced by the values of the fields it references. Custom field values by contrast are mutable and can be set directly by an API consumer. One key implication of this distinction is that computed attributes do not need to be stored per instance; we only need to define a per-model definition, which can be replicated for each instance. In this example, we just create a single attribute object tying our Jinja2 code to the site model. This allows us to render the attribute for every site. The only reason I can see to store the computed value for each instance would be as a performance optimization (essentially caching the rendered output). But considering the overhead associated with keeping these values up to date combined with the additional complexity of supporting read-only custom fields, this seems unlikely to be worthwhile except in very complex scenarios. Beyond the technical implementation, we must also consider the practical use case for such attributes: Given that APIs are intended to be consumed programmatically, what practical use cases can we identify that cannot be satisfied with the data already being provided. (As in the above example, the region and site names are already provided, and the client could render the custom attribute value independently.) Further, we would generally want to stop short of rendering any particular markup (e.g. HTML) as it could severely limit the practical application of the data being provided. > There is a lot of a data in one model (device), and most of can be shown in a table column. Again, it feels like the intended use case here is specifically for the user interface, which _is_ a valid consideration as it cannot be consumed programmatically. If anything, I would propose that the preferred implementation would be some mechanism by which custom attributes can be registered at the model level, and potentially conveyed as table columns and other elements in the user interface.
Author
Owner

@PieterL75 commented on GitHub (Feb 11, 2023):

I understand your point on the API part. CustomFields are not the right place to store this kind of formatting, as they are intended to store data related to the instance of the model. Each object of that model should be able to store different values in the CustomField.
My proposal does indeed require a different approach.

You're more in favor of a 'CustomColumn' or 'CustomAttribute' that links to a model. That attribute can be made available in the 'Configure Table' list, and it can also be returned as an attribute to a model in the API.
There could be different types of these (Text, Integer, URL, Badge, ProgressBar, ...)

@PieterL75 commented on GitHub (Feb 11, 2023): I understand your point on the API part. CustomFields are not the right place to store this kind of formatting, as they are intended to store data related to the instance of the model. Each object of that model should be able to store different values in the CustomField. My proposal does indeed require a different approach. You're more in favor of a 'CustomColumn' or 'CustomAttribute' that links to a model. That attribute can be made available in the 'Configure Table' list, and it can also be returned as an attribute to a model in the API. There could be different types of these (Text, Integer, URL, Badge, ProgressBar, ...)
Author
Owner

@jeremystretch commented on GitHub (Mar 16, 2023):

I'm going to close this out as the specific proposal herein is untenable, but I encourage anyone interested to submit a new FR proposing a feasible implementation of the desired functionality. This will likely require the introduction of a new model, which should be detailed accordingly.

@jeremystretch commented on GitHub (Mar 16, 2023): I'm going to close this out as the specific proposal herein is untenable, but I encourage anyone interested to submit a new FR proposing a feasible implementation of the desired functionality. This will likely require the introduction of a new model, which should be detailed accordingly.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/netbox#7620