Populating Extensibility Features¶
Added in version 1.2.0
In many cases, an app may wish to make use of Nautobot's various extensibility features, such as custom fields or relationships. It can be useful for an app to automatically create a custom field definition or relationship definition as a consequence of being installed and activated, so that everyday usage of the app can rely upon these definitions to be present.
To make this possible, Nautobot provides a custom signal, nautobot_database_ready
, that apps can register to listen for. This signal is triggered when nautobot-server migrate
or nautobot-server post_upgrade
is run after installing an app, and provides an opportunity for the app to make any desired additions to the database at this time.
For example, maybe we want our app to make use of a Relationship allowing each Location to be linked to our Animal model. We would define our callback function that makes sure this Relationship exists, by convention in a signals.py
file:
# signals.py
from nautobot.extras.choices import RelationshipTypeChoices
def create_location_to_animal_relationship(sender, apps, **kwargs):
"""Create a Location-to-Animal Relationship if it doesn't already exist."""
# Use apps.get_model to look up Nautobot core models
ContentType = apps.get_model("contenttypes", "ContentType")
Relationship = apps.get_model("extras", "Relationship")
Location = apps.get_model("dcim", "Location")
# Use sender.get_model to look up models from this app
Animal = sender.get_model("Animal")
# Ensure that the Relationship exists
Relationship.objects.update_or_create(
key="location_favorite_animal",
defaults={
"label": "Location's Favorite Animal",
"type": RelationshipTypeChoices.TYPE_ONE_TO_MANY,
"source_type": ContentType.objects.get_for_model(Animal),
"source_label": "Locations that love this Animal",
"destination_type": ContentType.objects.get_for_model(Location),
"destination_label": "Favorite Animal",
},
)
Then, in the NautobotAppConfig
ready()
function, we connect this callback function to the nautobot_database_ready
signal:
# __init__.py
from nautobot.apps import nautobot_database_ready, NautobotAppConfig
from .signals import create_location_to_animal_relationship
class AnimalSoundsConfig(NautobotAppConfig):
# ...
def ready(self):
super().ready()
nautobot_database_ready.connect(create_location_to_animal_relationship, sender=self)
config = AnimalSoundsConfig
Warning
It is crucial that you add the sender=self
parameter to the connect
method call - otherwise your signal handler will run as many times as the NautobotAppConfig.ready
method is called, which may be a lot of times.
After writing this code, run nautobot-server migrate
or nautobot-server post_upgrade
, then restart the Nautobot server, and you should see that this custom Relationship has now been automatically created.