NautobotUIViewSet¶
Added in version 1.4.0
New in Nautobot 1.4 is the debut of NautobotUIViewSet
: A powerful app development tool that can save app developer hundreds of lines of code compared to using legacy generic.views
. Using it to gain access to default functionalities previous provided by generic.views
such as create()
, update()
, partial_update()
, bulk_update()
, destroy()
, bulk_destroy()
, retrieve()
and list()
actions.
Note that this ViewSet is catered specifically to the UI, not the API.
Concrete examples on how to use NautobotUIViewSet
resides in nautobot.circuits.views
.
Below we provide an example on how to use NautobotUIViewSet
on a theoretical app model.
from nautobot.apps.views import NautobotUIViewSet
from yourapp import filters, forms, models, tables
from yourapp.api import serializers
class YourAppModelUIViewSet(NautobotUIViewSet):
bulk_update_form_class = forms.YourAppModelBulkEditForm
filterset_class = filters.YourAppModelFilterSet
filterset_form_class = forms.YourAppModelFilterForm
form_class = forms.YourAppModelForm
queryset = models.YourAppModel.objects.all()
serializer_class = serializers.YourAppModelSerializer
table_class = tables.YourAppModelTable
Setting ViewSet Attributes¶
One caveat of using the NautobotUIViewSet is that the queryset
, serializer_class
and table_class
attribute of the YourAppModelUIViewSet
has to be set before most of the NautobotUIViewSet
functionalities will become available.
By default the URL patterns generated by a NautobotUIViewSet
are based on the model's pk
(/model-name/<pk>/
for the detail view, /model-name/<pk>/edit/
for the edit view, etc.). if you need to use a different field to look up an object, just override the default lookup_field
in your ViewSet attributes:
from nautobot.apps.views import NautobotUIViewSet
class YourAppModelUIViewSet(NautobotUIViewSet):
...
lookup_field = "slug"
...
Changed in version 2.0.0
The default lookup_field
for NautobotUIViewSet
has been changed from "slug"
to "pk"
.
Note
Using a field other than the default pk
or the alternative field slug
(as shown in the example above), may result in certain pieces of the UI not displaying (for example, the edit and delete buttons on the object detail view). This is due to the URL expecting a named key of slug or pk, rather than id.
View Template Context¶
Templates can benefit from a very rich context passed down from the views and renderer, including forms, tables, as well as any other information that may be helpful for rendering templates. The keys it provides are as follows:
content_type
: The ContentType object for the associated modelfilter_form
: The FilterForm object for the associated modelform
: A Form object for the associated model if relevant (None
for list and detail/retrieve views)object
: An instance of the associated mode if available (None
for list and bulk operation views)permissions
: Summary of user permissions for the given modelreturn_url
: The relevant return URLtable
: A Table object for the associated model if relevant (None
for detail/retrieve and update views)table_config_form
: A TableConfigForm object for the associatedtable
, providing the ability to customize the tableverbose_name
: The singular form of the model's nameverbose_name_plural
: The plural form of the model's name
An example from editing a Provider object:
{
'content_type': <ContentType: circuits | provider>,
'filter_form': <ProviderFilterForm bound=True, valid=Unknown, fields=(location;q;asn;tag)>,
'form': <ProviderForm bound=False, valid=Unknown, fields=(name;asn;account;portal_url;noc_contact;admin_contact;comments;tags;object_note)>,
'object': <Provider: NautobotProvider>,
'permissions': {'add': True, 'change': True, 'delete': True, 'view': True},
'return_url': '/circuits/providers/nautobotprovider',
'table': None,
'table_config_form': None,
'verbose_name': 'provider',
'verbose_name_plural': 'providers'
}
Other context keys may be available for certain views:
editing
: Provided for create and update views to help the template determine if this is a new or existing objectaction_buttons
: Provided for the list view for the top of table buttons (such as "Add" and "Export")
You may see other context keys as well, but any not documented above should not be relied upon as they may be removed in a future release. Some examples of those are:
obj
: Please useobject
insteadobj_type
: Please useverbose_name
insteadobj_type_plural
: Please useverbose_name_plural
instead
Removed in version 2.0.0
The changelog_url
context key was removed. Use object.get_changelog_url
instead.
Excluding ViewMixins from NautobotUIViewSet¶
For app models that do not require certain views, simply inherit directly from the ViewMixin
classes available in nautobot.apps.views
instead of NautobotUIViewSet
.
Concrete examples for excluding ViewMixins
, checkout CircuitTerminationUIViewSet
and CircuitTypeUIViewSet
in nautobot.circuits.views
.
## An app model viewset that does not support bulk views and operations
import nautobot.apps.views
class YourAppModelUIViewSet(
nautobot.apps.views.ObjectListViewMixin,
nautobot.apps.views.ObjectDetailViewMixin,
nautobot.apps.views.ObjectEditViewMixin,
nautobot.apps.views.ObjectDestroyViewMixin,
):
filterset_class = YourAppModelFilterSet
filterset_form_class = YourAppModelFilterForm
form_class = YourAppModelForm
queryset = YourAppModel.objects.all()
serializer_class = serializers.YourAppModelSerializer
table_class = YourAppModelTable
# You do not need to specify attributes that are not needed.
Excluding unwanted urls from NautobotUIViewSetRouter
is done for you at the ViewSet level. If you do not inherit the unwanted ViewMixins, the corresponding route from the router will not be published.
# urls.py
# All the urls correspond to BulkViewMixins will not be published when you register your ViewSet with the router.
router.register("yourappmodel", views.YourAppModelUIViewSet)
Template Naming for NautobotUIViewSet¶
Template naming is very intuitive in NautobotUIViewSet. In templates/yourapp
folder, name your templates following the convention {model_name}_{action}.html
.
ViewMixins | action |
---|---|
ObjectListViewMixin | list |
ObjectDetailViewMixin | retrieve |
ObjectEditViewMixin | create/update |
ObjectDestroyViewMixin | destroy |
ObjectBulkDestroyViewMixin | bulk_destroy |
ObjectBulkUpdateViewMixin | bulk_update |
Removed in version 2.2.0
ObjectBulkCreateViewMixin is deprecated as its functionality has been replaced by a system Job. It will be removed from the code base entirely in Nautobot 3.0.
For example, for a DetailView template for YourAppModel
, the template name will be yourapp/yourappmodel_retrieve.html
, for a BulkUpdateView template for yourappmodel
, the template name will be yourapp/yourappmodel_bulk_update.html
and etc.
If you do not provide your own templates in the yourapp/templates/yourapp
folder, NautobotUIViewSet
will fall back to generic/object_{self.action}.html
.
Since in many cases the create
and update
templates for a model will be identical, you are not required to create both. If you provide a {app_label}/{model_opts.model_name}_create.html
file but not a {app_label}/{model_opts.model_name}_update.html
file, then when you update an object, it will fall back to {app_label}/{model_opts.model_name}_create.html
and vice versa.
Adding Custom Views To NautobotUIViewSet & NautobotUIViewSetRouter¶
Changed in version 1.6.0
Via PR #4045, notes and changelog views provided by mixins have now been moved to this pattern.
Django REST Framework provides the ability to decorate a method on a ViewSet with @action(detail=True)
to add the method as a view to the ViewSetRouter. This method must return a fully rendered HTML view.
Below is an example of adding a custom action view to an App's ViewSet. A few considerations to keep in mind:
- The method name is the
action
in Django REST Framework terms. - The
action
will be used for template lookup - The
action
will be used for URL naming and construction (plugins:<app>:<model>_<action>
,/plugins/<app>/<model>/<uuid>/<action>/
). - The
action
will be used as a custom permission that users must have (<app>.<action>_<model>
)
In the below example:
- The expected template must be named
yourapp/yourappmodel_customview.html
- The reversible URL name will be
plugins:yourapp:yourappmodel_customview
- The URL pattern will be
/plugins/yourapp/yourappmodel/<uuid>/customview/
- Users will need
yourapp.customview_yourappmodel
permission to access this view.
from nautobot.apps.views import NautobotUIViewSet
from rest_framework.decorators import action
from rest_framework.response import Response
from yourapp import filters, forms, models, tables
from yourapp.api import serializers
class YourAppModelUIViewSet(NautobotUIViewSet):
bulk_update_form_class = forms.YourAppModelBulkEditForm
filterset_class = filters.YourAppModelFilterSet
filterset_form_class = forms.YourAppModelFilterForm
form_class = forms.YourAppModelForm
queryset = models.YourAppModel.objects.all()
serializer_class = serializers.YourAppModelSerializer
table_class = tables.YourAppModelTable
@action(detail=True)
def customview(self, request, *args, **kwargs):
"""Context passed to template for rendering.
Expected URL pattern will be `/plugins/yourapp/yourappmodel/<uuid>/customview/`
"""
context = {
"some_key": "some value",
}
return Response(context)