diff --git a/netbox/circuits/views.py b/netbox/circuits/views.py index b549b3a01..2f1addab1 100644 --- a/netbox/circuits/views.py +++ b/netbox/circuits/views.py @@ -320,7 +320,7 @@ class CircuitTerminationEditView(generic.ObjectEditView): model_form = forms.CircuitTerminationForm template_name = 'circuits/circuittermination_edit.html' - def alter_obj(self, obj, request, url_args, url_kwargs): + def alter_object(self, obj, request, url_args, url_kwargs): if 'circuit' in url_kwargs: obj.circuit = get_object_or_404(Circuit, pk=url_kwargs['circuit']) return obj diff --git a/netbox/dcim/views.py b/netbox/dcim/views.py index b1a53e93c..6fb3e2a00 100644 --- a/netbox/dcim/views.py +++ b/netbox/dcim/views.py @@ -671,7 +671,7 @@ class RackReservationEditView(generic.ObjectEditView): queryset = RackReservation.objects.all() model_form = forms.RackReservationForm - def alter_obj(self, obj, request, args, kwargs): + def alter_object(self, obj, request, args, kwargs): if not obj.pk: if 'rack' in request.GET: obj.rack = get_object_or_404(Rack, pk=request.GET.get('rack')) @@ -2342,7 +2342,7 @@ class CableCreateView(generic.ObjectEditView): return super().dispatch(request, *args, **kwargs) - def alter_obj(self, obj, request, url_args, url_kwargs): + def alter_object(self, obj, request, url_args, url_kwargs): termination_a_type = url_kwargs.get('termination_a_type') termination_a_id = url_kwargs.get('termination_a_id') termination_b_type_name = url_kwargs.get('termination_b_type') @@ -2355,7 +2355,8 @@ class CableCreateView(generic.ObjectEditView): return obj def get(self, request, *args, **kwargs): - obj = self.alter_obj(self.get_object(kwargs), request, args, kwargs) + obj = self.get_object(**kwargs) + obj = self.alter_object(obj, request, args, kwargs) # Parse initial data manually to avoid setting field values as lists initial_data = {k: request.GET[k] for k in request.GET} @@ -2423,7 +2424,7 @@ class ConsoleConnectionsListView(generic.ObjectListView): template_name = 'dcim/connections_list.html' action_buttons = ('export',) - def extra_context(self): + def get_extra_context(self, request): return { 'title': 'Console Connections' } @@ -2437,7 +2438,7 @@ class PowerConnectionsListView(generic.ObjectListView): template_name = 'dcim/connections_list.html' action_buttons = ('export',) - def extra_context(self): + def get_extra_context(self, request): return { 'title': 'Power Connections' } @@ -2451,7 +2452,7 @@ class InterfaceConnectionsListView(generic.ObjectListView): template_name = 'dcim/connections_list.html' action_buttons = ('export',) - def extra_context(self): + def get_extra_context(self, request): return { 'title': 'Interface Connections' } diff --git a/netbox/extras/views.py b/netbox/extras/views.py index ab9e3ba52..4382d1fbb 100644 --- a/netbox/extras/views.py +++ b/netbox/extras/views.py @@ -472,7 +472,7 @@ class ImageAttachmentEditView(generic.ObjectEditView): queryset = ImageAttachment.objects.all() model_form = forms.ImageAttachmentForm - def alter_obj(self, instance, request, args, kwargs): + def alter_object(self, instance, request, args, kwargs): if not instance.pk: # Assign the parent object based on URL kwargs content_type = get_object_or_404(ContentType, pk=request.GET.get('content_type')) @@ -510,7 +510,7 @@ class JournalEntryEditView(generic.ObjectEditView): queryset = JournalEntry.objects.all() model_form = forms.JournalEntryForm - def alter_obj(self, obj, request, args, kwargs): + def alter_object(self, obj, request, args, kwargs): if not obj.pk: obj.created_by = request.user return obj diff --git a/netbox/ipam/views.py b/netbox/ipam/views.py index c172caf0b..6d3963599 100644 --- a/netbox/ipam/views.py +++ b/netbox/ipam/views.py @@ -721,7 +721,7 @@ class IPAddressEditView(generic.ObjectEditView): model_form = forms.IPAddressForm template_name = 'ipam/ipaddress_edit.html' - def alter_obj(self, obj, request, url_args, url_kwargs): + def alter_object(self, obj, request, url_args, url_kwargs): if 'interface' in request.GET: try: @@ -975,7 +975,7 @@ class FHRPGroupAssignmentEditView(generic.ObjectEditView): model_form = forms.FHRPGroupAssignmentForm template_name = 'ipam/fhrpgroupassignment_edit.html' - def alter_obj(self, instance, request, args, kwargs): + def alter_object(self, instance, request, args, kwargs): if not instance.pk: # Assign the interface based on URL kwargs content_type = get_object_or_404(ContentType, pk=request.GET.get('interface_type')) @@ -1092,7 +1092,7 @@ class ServiceEditView(generic.ObjectEditView): model_form = forms.ServiceForm template_name = 'ipam/service_edit.html' - def alter_obj(self, obj, request, url_args, url_kwargs): + def alter_object(self, obj, request, url_args, url_kwargs): if 'device' in url_kwargs: obj.device = get_object_or_404( Device.objects.restrict(request.user), diff --git a/netbox/netbox/views/generic.py b/netbox/netbox/views/generic.py index 1c2ff9917..83eabdb23 100644 --- a/netbox/netbox/views/generic.py +++ b/netbox/netbox/views/generic.py @@ -55,14 +55,16 @@ class ObjectView(ObjectPermissionRequiredMixin, View): """ Return any additional context data for the template. - request: The current request - instance: The object being viewed + :param request: The current request + :param instance: The object being viewed """ return {} def get(self, request, *args, **kwargs): """ - Generic GET handler for accessing an object by PK or slug + GET request handler. *args and **kwargs are passed to identify the object being queried. + + :param request: The current request """ instance = get_object_or_404(self.queryset, **kwargs) @@ -78,10 +80,11 @@ class ObjectListView(ObjectPermissionRequiredMixin, View): queryset: The queryset of objects to display. Note: Prefetching related objects is not necessary, as the table will prefetch objects as needed depending on the columns being displayed. - filter: A django-filter FilterSet that is applied to the queryset - filter_form: The form used to render filter options + filterset: A django-filter FilterSet that is applied to the queryset + filterset_form: The form used to render filter options table: The django-tables2 Table used to render the objects list template_name: The name of the template + action_buttons: A list of buttons to include at the top of the page """ queryset = None filterset = None @@ -94,6 +97,13 @@ class ObjectListView(ObjectPermissionRequiredMixin, View): return get_permission_for_model(self.queryset.model, 'view') def get_table(self, request, permissions): + """ + Return the django-tables2 Table instance to be used for rendering the objects list. + + :param request: The current request + :param permissions: A dictionary mapping of the view, add, change, and delete permissions to booleans indicating + whether the user has each + """ table = self.table(self.queryset, user=request.user) if 'pk' in table.base_columns and (permissions['change'] or permissions['delete']): table.columns.show('pk') @@ -143,7 +153,20 @@ class ObjectListView(ObjectPermissionRequiredMixin, View): messages.error(request, f"There was an error rendering the selected export template ({template.name}): {e}") return redirect(request.path) + def get_extra_context(self, request): + """ + Return any additional context data for the template. + + :param request: The current request + """ + return {} + def get(self, request): + """ + GET request handler. + + :param request: The current request + """ model = self.queryset.model content_type = ContentType.objects.get_for_model(model) @@ -192,19 +215,16 @@ class ObjectListView(ObjectPermissionRequiredMixin, View): 'action_buttons': self.action_buttons, 'filter_form': self.filterset_form(request.GET, label_suffix='') if self.filterset_form else None, } - context.update(self.extra_context()) + context.update(self.get_extra_context(request)) return render(request, self.template_name, context) - def extra_context(self): - return {} - class ObjectEditView(GetReturnURLMixin, ObjectPermissionRequiredMixin, View): """ Create or edit a single object. - queryset: The base queryset for the object being modified + queryset: The base QuerySet for the object being modified model_form: The form used to create or edit the object template_name: The name of the template """ @@ -217,25 +237,31 @@ class ObjectEditView(GetReturnURLMixin, ObjectPermissionRequiredMixin, View): # we are modifying an existing object or creating a new one. return get_permission_for_model(self.queryset.model, self._permission_action) - def get_object(self, kwargs): - # Look up an existing object by slug or PK, if provided. - if 'slug' in kwargs: - obj = get_object_or_404(self.queryset, slug=kwargs['slug']) - elif 'pk' in kwargs: - obj = get_object_or_404(self.queryset, pk=kwargs['pk']) - # Otherwise, return a new instance. - else: - return self.queryset.model() + def get_object(self, **kwargs): + """ + Return an instance for editing. If a PK has been specified, this will be an existing object. - # Take a snapshot of change-logged models - if hasattr(obj, 'snapshot'): - obj.snapshot() + :param kwargs: URL path kwargs + """ + if 'pk' in kwargs: + obj = get_object_or_404(self.queryset, **kwargs) + # Take a snapshot of change-logged models + if hasattr(obj, 'snapshot'): + obj.snapshot() + return obj - return obj + return self.queryset.model() - def alter_obj(self, obj, request, url_args, url_kwargs): - # Allow views to add extra info to an object before it is processed. For example, a parent object can be defined - # given some parameter from the request URL. + def alter_object(self, obj, request, url_args, url_kwargs): + """ + Provides a hook for views to modify an object before it is processed. For example, a parent object can be + defined given some parameter from the request URL. + + :param obj: The object being edited + :param request: The current request + :param url_args: URL path args + :param url_kwargs: URL path kwargs + """ return obj def dispatch(self, request, *args, **kwargs): @@ -245,7 +271,13 @@ class ObjectEditView(GetReturnURLMixin, ObjectPermissionRequiredMixin, View): return super().dispatch(request, *args, **kwargs) def get(self, request, *args, **kwargs): - obj = self.alter_obj(self.get_object(kwargs), request, args, kwargs) + """ + GET request handler. + + :param request: The current request + """ + obj = self.get_object(**kwargs) + obj = self.alter_object(obj, request, args, kwargs) initial_data = normalize_querydict(request.GET) form = self.model_form(instance=obj, initial=initial_data) @@ -259,8 +291,15 @@ class ObjectEditView(GetReturnURLMixin, ObjectPermissionRequiredMixin, View): }) def post(self, request, *args, **kwargs): + """ + POST request handler. + + :param request: The current request + """ logger = logging.getLogger('netbox.views.ObjectEditView') - obj = self.alter_obj(self.get_object(kwargs), request, args, kwargs) + obj = self.get_object(**kwargs) + obj = self.alter_object(obj, request, args, kwargs) + form = self.model_form( data=request.POST, files=request.FILES, @@ -334,12 +373,13 @@ class ObjectDeleteView(GetReturnURLMixin, ObjectPermissionRequiredMixin, View): def get_required_permission(self): return get_permission_for_model(self.queryset.model, 'delete') - def get_object(self, kwargs): - # Look up object by slug if one has been provided. Otherwise, use PK. - if 'slug' in kwargs: - obj = get_object_or_404(self.queryset, slug=kwargs['slug']) - else: - obj = get_object_or_404(self.queryset, pk=kwargs['pk']) + def get_object(self, **kwargs): + """ + Return an instance for deletion. If a PK has been specified, this will be an existing object. + + :param kwargs: URL path kwargs + """ + obj = get_object_or_404(self.queryset, **kwargs) # Take a snapshot of change-logged models if hasattr(obj, 'snapshot'): @@ -347,8 +387,13 @@ class ObjectDeleteView(GetReturnURLMixin, ObjectPermissionRequiredMixin, View): return obj - def get(self, request, **kwargs): - obj = self.get_object(kwargs) + def get(self, request, *args, **kwargs): + """ + GET request handler. + + :param request: The current request + """ + obj = self.get_object(**kwargs) form = ConfirmationForm(initial=request.GET) return render(request, self.template_name, { @@ -358,9 +403,14 @@ class ObjectDeleteView(GetReturnURLMixin, ObjectPermissionRequiredMixin, View): 'return_url': self.get_return_url(request, obj), }) - def post(self, request, **kwargs): + def post(self, request, *args, **kwargs): + """ + POST request handler. + + :param request: The current request + """ logger = logging.getLogger('netbox.views.ObjectDeleteView') - obj = self.get_object(kwargs) + obj = self.get_object(**kwargs) form = ConfirmationForm(request.POST) if form.is_valid(): diff --git a/netbox/tenancy/views.py b/netbox/tenancy/views.py index c848de47f..b41af62ee 100644 --- a/netbox/tenancy/views.py +++ b/netbox/tenancy/views.py @@ -353,7 +353,7 @@ class ContactAssignmentEditView(generic.ObjectEditView): model_form = forms.ContactAssignmentForm template_name = 'tenancy/contactassignment_edit.html' - def alter_obj(self, instance, request, args, kwargs): + def alter_object(self, instance, request, args, kwargs): if not instance.pk: # Assign the object based on URL kwargs content_type = get_object_or_404(ContentType, pk=request.GET.get('content_type'))