Repository: netbox-community/netbox
Pull request: #10170 optimize change log queries
<!--
    Thank you for your interest in contributing to NetBox! Please note
    that our contribution policy requires that a feature request or bug
    report be approved and assigned prior to filing a pull request. This
    helps avoid wasting time and effort on something that we might not
    be able to accept.

    Please indicate the assigned feature request or bug report below.
    IF YOUR PULL REQUEST DOES NOT REFERENCE AN ISSUE WHICH HAS BEEN ASSIGNED
    TO YOU, IT WE BE CLOSED AUTOMATICALLY. For example:

    ### Fixes:
-->
### Fixes:  #10170
<!--
    Please include a summary of the proposed changes below.
-->
Adds some better accessors to ObjectChangeTable to make the Change Log better performing.

Problem statement:
Change Log list view has inefficient query
### Proposed Changes

need to add some select_related and prefetch_related to the Change Log list view to reduce the number of SQL queries.

### Justification

On the demo site noticed the Change log list view was somewhat slow, checking in the debug toolbar with demo data saw it was generating over 100 SQL queries.  For longer lists it will just get slower.

Hints from issue discussion:
> need to add some select_related and prefetch_related to the Change Log list view

This is typically unnecessary as the dynamic table rendering takes care of attaching prefetches automatically depending on what columns have been selected for display. In this case, there's a bug with the `full_name` column where its template code is referencing `record.user.get_full_name`. We can fix this by setting the accessor for the column to the `user` field and tweaking the template code accordingly. The table will then pick up on the relation to the User model and attach the necessary prefetch to the queryset. This seems to be the case for `changed_object` as well.

Commit message: #10170 changes from code review

Patch to review:
diff --git a/netbox/extras/tables/tables.py b/netbox/extras/tables/tables.py
index 2fa13f98a06..8ac1f7865d8 100644
--- a/netbox/extras/tables/tables.py
+++ b/netbox/extras/tables/tables.py
@@ -183,6 +183,7 @@ class ObjectChangeTable(NetBoxTable):
         verbose_name='Username'
     )
     full_name = tables.TemplateColumn(
+        accessor=tables.A('user'),
         template_code=OBJECTCHANGE_FULL_NAME,
         verbose_name='Full Name',
         orderable=False
@@ -192,6 +193,7 @@ class ObjectChangeTable(NetBoxTable):
         verbose_name='Type'
     )
     object_repr = tables.TemplateColumn(
+        accessor=tables.A('object_repr'),
         template_code=OBJECTCHANGE_OBJECT,
         verbose_name='Object'
     )
diff --git a/netbox/extras/tables/template_code.py b/netbox/extras/tables/template_code.py
index 4eec85bddf7..a848b60414a 100644
--- a/netbox/extras/tables/template_code.py
+++ b/netbox/extras/tables/template_code.py
@@ -13,8 +13,8 @@
 """
 
 OBJECTCHANGE_OBJECT = """
-{% if record.changed_object and record.changed_object.get_absolute_url %}
-    <a href="{{ record.changed_object.get_absolute_url }}">{{ record.object_repr }}</a>
+{% if value.changed_object and value.changed_object.get_absolute_url %}
+    <a href="{{ value.changed_object.get_absolute_url }}">{{ record.object_repr }}</a>
 {% else %}
     {{ record.object_repr }}
 {% endif %}


Code review comments:
diff_hunk: @@ -192,6 +193,7 @@ class ObjectChangeTable(NetBoxTable):
         verbose_name='Type'
     )
     object_repr = tables.TemplateColumn(
+        accessor=tables.A('object_repr'),
path: netbox/extras/tables/tables.py
text: @user1:
Here we want to override the column's default accessor (the instance's `object_repr` attribute) with `changed_object`, to ensure that it gets picked up by the table for prefetching.

```suggestion
        accessor=tables.A('changed_object'),
```

diff_hunk: @@ -13,8 +13,8 @@
 """
 
 OBJECTCHANGE_OBJECT = """
-{% if record.changed_object and record.changed_object.get_absolute_url %}
-    <a href="{{ record.changed_object.get_absolute_url }}">{{ record.object_repr }}</a>
+{% if value.changed_object and value.changed_object.get_absolute_url %}
+    <a href="{{ value.changed_object.get_absolute_url }}">{{ record.object_repr }}</a>
path: netbox/extras/tables/template_code.py
text: @user1:
```suggestion
{% if value and value.get_absolute_url %}
    <a href="{{ value.get_absolute_url }}">{{ record.object_repr }}</a>
```