prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  HTMX: Bulk actions in ObjectListView without function
  ### Deployment Type
  
  Self-hosted
  
  ### NetBox Version
  
  v4.0-beta1
  
  ### Python Version
  
  3.11
  
  ### Steps to Reproduce
  
  1. Set user preferences to HTMX Navigation enabled
  2. Create two or more IP addresses
  3. Select the IP addresses in list view
  4. Click on "Edit Selected" or "Delete Selected"
  
  ### Expected Behavior
  
  For "Edit Selected", the bulk edit form opens. For "Delete Selected", the usual "xxx Objects will be deleted" confirmation dialog appears.
  
  ### Observed Behavior
  
  Nothing at all happens.
  
  With "HTMX Navigation" set to "disabled", everything works as usual.
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `netbox/utilities/templatetags/buttons.py`
  Content:
  ```
  1 from django import template
  2 from django.contrib.contenttypes.models import ContentType
  3 from django.urls import NoReverseMatch, reverse
  4 
  5 from core.models import ObjectType
  6 from extras.models import Bookmark, ExportTemplate
  7 from utilities.querydict import prepare_cloned_fields
  8 from utilities.views import get_viewname
  9 
  10 __all__ = (
  11     'add_button',
  12     'bookmark_button',
  13     'bulk_delete_button',
  14     'bulk_edit_button',
  15     'clone_button',
  16     'delete_button',
  17     'edit_button',
  18     'export_button',
  19     'import_button',
  20     'sync_button',
  21 )
  22 
  23 register = template.Library()
  24 
  25 
  26 #
  27 # Instance buttons
  28 #
  29 
  30 @register.inclusion_tag('buttons/bookmark.html', takes_context=True)
  31 def bookmark_button(context, instance):
  32     # Check if this user has already bookmarked the object
  33     content_type = ContentType.objects.get_for_model(instance)
  34     bookmark = Bookmark.objects.filter(
  35         object_type=content_type,
  36         object_id=instance.pk,
  37         user=context['request'].user
  38     ).first()
  39 
  40     # Compile form URL & data
  41     if bookmark:
  42         form_url = reverse('extras:bookmark_delete', kwargs={'pk': bookmark.pk})
  43         form_data = {
  44             'confirm': 'true',
  45         }
  46     else:
  47         form_url = reverse('extras:bookmark_add')
  48         form_data = {
  49             'object_type': content_type.pk,
  50             'object_id': instance.pk,
  51         }
  52 
  53     return {
  54         'bookmark': bookmark,
  55         'form_url': form_url,
  56         'form_data': form_data,
  57         'return_url': instance.get_absolute_url(),
  58     }
  59 
  60 
  61 @register.inclusion_tag('buttons/clone.html')
  62 def clone_button(instance):
  63     url = reverse(get_viewname(instance, 'add'))
  64 
  65     # Populate cloned field values
  66     param_string = prepare_cloned_fields(instance).urlencode()
  67     if param_string:
  68         url = f'{url}?{param_string}'
  69     else:
  70         url = None
  71 
  72     return {
  73         'url': url,
  74     }
  75 
  76 
  77 @register.inclusion_tag('buttons/edit.html')
  78 def edit_button(instance):
  79     viewname = get_viewname(instance, 'edit')
  80     url = reverse(viewname, kwargs={'pk': instance.pk})
  81 
  82     return {
  83         'url': url,
  84     }
  85 
  86 
  87 @register.inclusion_tag('buttons/delete.html')
  88 def delete_button(instance):
  89     viewname = get_viewname(instance, 'delete')
  90     url = reverse(viewname, kwargs={'pk': instance.pk})
  91 
  92     return {
  93         'url': url,
  94     }
  95 
  96 
  97 @register.inclusion_tag('buttons/sync.html')
  98 def sync_button(instance):
  99     viewname = get_viewname(instance, 'sync')
  100     url = reverse(viewname, kwargs={'pk': instance.pk})
  101 
  102     return {
  103         'url': url,
  104     }
  105 
  106 
  107 #
  108 # List buttons
  109 #
  110 
  111 @register.inclusion_tag('buttons/add.html')
  112 def add_button(model, action='add'):
  113     try:
  114         url = reverse(get_viewname(model, action))
  115     except NoReverseMatch:
  116         url = None
  117 
  118     return {
  119         'url': url,
  120     }
  121 
  122 
  123 @register.inclusion_tag('buttons/import.html')
  124 def import_button(model, action='import'):
  125     try:
  126         url = reverse(get_viewname(model, action))
  127     except NoReverseMatch:
  128         url = None
  129 
  130     return {
  131         'url': url,
  132     }
  133 
  134 
  135 @register.inclusion_tag('buttons/export.html', takes_context=True)
  136 def export_button(context, model):
  137     object_type = ObjectType.objects.get_for_model(model)
  138     user = context['request'].user
  139 
  140     # Determine if the "all data" export returns CSV or YAML
  141     data_format = 'YAML' if hasattr(object_type.model_class(), 'to_yaml') else 'CSV'
  142 
  143     # Retrieve all export templates for this model
  144     export_templates = ExportTemplate.objects.restrict(user, 'view').filter(object_types=object_type)
  145 
  146     return {
  147         'perms': context['perms'],
  148         'object_type': object_type,
  149         'url_params': context['request'].GET.urlencode() if context['request'].GET else '',
  150         'export_templates': export_templates,
  151         'data_format': data_format,
  152     }
  153 
  154 
  155 @register.inclusion_tag('buttons/bulk_edit.html')
  156 def bulk_edit_button(model, action='bulk_edit', query_params=None):
  157     try:
  158         url = reverse(get_viewname(model, action))
  159         if query_params:
  160             url = f'{url}?{query_params.urlencode()}'
  161     except NoReverseMatch:
  162         url = None
  163 
  164     return {
  165         'url': url,
  166     }
  167 
  168 
  169 @register.inclusion_tag('buttons/bulk_delete.html')
  170 def bulk_delete_button(model, action='bulk_delete', query_params=None):
  171     try:
  172         url = reverse(get_viewname(model, action))
  173         if query_params:
  174             url = f'{url}?{query_params.urlencode()}'
  175     except NoReverseMatch:
  176         url = None
  177 
  178     return {
  179         'url': url,
  180     }
  181
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/netbox/utilities/templatetags/buttons.py b/netbox/utilities/templatetags/buttons.py
  --- a/netbox/utilities/templatetags/buttons.py
  +++ b/netbox/utilities/templatetags/buttons.py
  @@ -152,8 +152,8 @@
       }
   
   
  -@register.inclusion_tag('buttons/bulk_edit.html')
  -def bulk_edit_button(model, action='bulk_edit', query_params=None):
  +@register.inclusion_tag('buttons/bulk_edit.html', takes_context=True)
  +def bulk_edit_button(context, model, action='bulk_edit', query_params=None):
       try:
           url = reverse(get_viewname(model, action))
           if query_params:
  @@ -162,12 +162,13 @@
           url = None
   
       return {
  +        'htmx_navigation': context.get('htmx_navigation'),
           'url': url,
       }
   
   
  -@register.inclusion_tag('buttons/bulk_delete.html')
  -def bulk_delete_button(model, action='bulk_delete', query_params=None):
  +@register.inclusion_tag('buttons/bulk_delete.html', takes_context=True)
  +def bulk_delete_button(context, model, action='bulk_delete', query_params=None):
       try:
           url = reverse(get_viewname(model, action))
           if query_params:
  @@ -176,5 +177,6 @@
           url = None
   
       return {
  +        'htmx_navigation': context.get('htmx_navigation'),
           'url': url,
       }
  
verification_info: {"golden_diff": "diff --git a/netbox/utilities/templatetags/buttons.py b/netbox/utilities/templatetags/buttons.py\n--- a/netbox/utilities/templatetags/buttons.py\n+++ b/netbox/utilities/templatetags/buttons.py\n@@ -152,8 +152,8 @@\n     }\n \n \n-@register.inclusion_tag('buttons/bulk_edit.html')\n-def bulk_edit_button(model, action='bulk_edit', query_params=None):\n+@register.inclusion_tag('buttons/bulk_edit.html', takes_context=True)\n+def bulk_edit_button(context, model, action='bulk_edit', query_params=None):\n     try:\n         url = reverse(get_viewname(model, action))\n         if query_params:\n@@ -162,12 +162,13 @@\n         url = None\n \n     return {\n+        'htmx_navigation': context.get('htmx_navigation'),\n         'url': url,\n     }\n \n \n-@register.inclusion_tag('buttons/bulk_delete.html')\n-def bulk_delete_button(model, action='bulk_delete', query_params=None):\n+@register.inclusion_tag('buttons/bulk_delete.html', takes_context=True)\n+def bulk_delete_button(context, model, action='bulk_delete', query_params=None):\n     try:\n         url = reverse(get_viewname(model, action))\n         if query_params:\n@@ -176,5 +177,6 @@\n         url = None\n \n     return {\n+        'htmx_navigation': context.get('htmx_navigation'),\n         'url': url,\n     }\n", "issue": "HTMX: Bulk actions in ObjectListView without function\n### Deployment Type\n\nSelf-hosted\n\n### NetBox Version\n\nv4.0-beta1\n\n### Python Version\n\n3.11\n\n### Steps to Reproduce\n\n1. Set user preferences to HTMX Navigation enabled\r\n2. Create two or more IP addresses\r\n3. Select the IP addresses in list view\r\n4. Click on \"Edit Selected\" or \"Delete Selected\"\n\n### Expected Behavior\n\nFor \"Edit Selected\", the bulk edit form opens. For \"Delete Selected\", the usual \"xxx Objects will be deleted\" confirmation dialog appears.\n\n### Observed Behavior\n\nNothing at all happens.\r\n\r\nWith \"HTMX Navigation\" set to \"disabled\", everything works as usual.\n", "before_files": [{"content": "from django import template\nfrom django.contrib.contenttypes.models import ContentType\nfrom django.urls import NoReverseMatch, reverse\n\nfrom core.models import ObjectType\nfrom extras.models import Bookmark, ExportTemplate\nfrom utilities.querydict import prepare_cloned_fields\nfrom utilities.views import get_viewname\n\n__all__ = (\n    'add_button',\n    'bookmark_button',\n    'bulk_delete_button',\n    'bulk_edit_button',\n    'clone_button',\n    'delete_button',\n    'edit_button',\n    'export_button',\n    'import_button',\n    'sync_button',\n)\n\nregister = template.Library()\n\n\n#\n# Instance buttons\n#\n\n@register.inclusion_tag('buttons/bookmark.html', takes_context=True)\ndef bookmark_button(context, instance):\n    # Check if this user has already bookmarked the object\n    content_type = ContentType.objects.get_for_model(instance)\n    bookmark = Bookmark.objects.filter(\n        object_type=content_type,\n        object_id=instance.pk,\n        user=context['request'].user\n    ).first()\n\n    # Compile form URL & data\n    if bookmark:\n        form_url = reverse('extras:bookmark_delete', kwargs={'pk': bookmark.pk})\n        form_data = {\n            'confirm': 'true',\n        }\n    else:\n        form_url = reverse('extras:bookmark_add')\n        form_data = {\n            'object_type': content_type.pk,\n            'object_id': instance.pk,\n        }\n\n    return {\n        'bookmark': bookmark,\n        'form_url': form_url,\n        'form_data': form_data,\n        'return_url': instance.get_absolute_url(),\n    }\n\n\n@register.inclusion_tag('buttons/clone.html')\ndef clone_button(instance):\n    url = reverse(get_viewname(instance, 'add'))\n\n    # Populate cloned field values\n    param_string = prepare_cloned_fields(instance).urlencode()\n    if param_string:\n        url = f'{url}?{param_string}'\n    else:\n        url = None\n\n    return {\n        'url': url,\n    }\n\n\n@register.inclusion_tag('buttons/edit.html')\ndef edit_button(instance):\n    viewname = get_viewname(instance, 'edit')\n    url = reverse(viewname, kwargs={'pk': instance.pk})\n\n    return {\n        'url': url,\n    }\n\n\n@register.inclusion_tag('buttons/delete.html')\ndef delete_button(instance):\n    viewname = get_viewname(instance, 'delete')\n    url = reverse(viewname, kwargs={'pk': instance.pk})\n\n    return {\n        'url': url,\n    }\n\n\n@register.inclusion_tag('buttons/sync.html')\ndef sync_button(instance):\n    viewname = get_viewname(instance, 'sync')\n    url = reverse(viewname, kwargs={'pk': instance.pk})\n\n    return {\n        'url': url,\n    }\n\n\n#\n# List buttons\n#\n\n@register.inclusion_tag('buttons/add.html')\ndef add_button(model, action='add'):\n    try:\n        url = reverse(get_viewname(model, action))\n    except NoReverseMatch:\n        url = None\n\n    return {\n        'url': url,\n    }\n\n\n@register.inclusion_tag('buttons/import.html')\ndef import_button(model, action='import'):\n    try:\n        url = reverse(get_viewname(model, action))\n    except NoReverseMatch:\n        url = None\n\n    return {\n        'url': url,\n    }\n\n\n@register.inclusion_tag('buttons/export.html', takes_context=True)\ndef export_button(context, model):\n    object_type = ObjectType.objects.get_for_model(model)\n    user = context['request'].user\n\n    # Determine if the \"all data\" export returns CSV or YAML\n    data_format = 'YAML' if hasattr(object_type.model_class(), 'to_yaml') else 'CSV'\n\n    # Retrieve all export templates for this model\n    export_templates = ExportTemplate.objects.restrict(user, 'view').filter(object_types=object_type)\n\n    return {\n        'perms': context['perms'],\n        'object_type': object_type,\n        'url_params': context['request'].GET.urlencode() if context['request'].GET else '',\n        'export_templates': export_templates,\n        'data_format': data_format,\n    }\n\n\n@register.inclusion_tag('buttons/bulk_edit.html')\ndef bulk_edit_button(model, action='bulk_edit', query_params=None):\n    try:\n        url = reverse(get_viewname(model, action))\n        if query_params:\n            url = f'{url}?{query_params.urlencode()}'\n    except NoReverseMatch:\n        url = None\n\n    return {\n        'url': url,\n    }\n\n\n@register.inclusion_tag('buttons/bulk_delete.html')\ndef bulk_delete_button(model, action='bulk_delete', query_params=None):\n    try:\n        url = reverse(get_viewname(model, action))\n        if query_params:\n            url = f'{url}?{query_params.urlencode()}'\n    except NoReverseMatch:\n        url = None\n\n    return {\n        'url': url,\n    }\n", "path": "netbox/utilities/templatetags/buttons.py"}], "after_files": [{"content": "from django import template\nfrom django.contrib.contenttypes.models import ContentType\nfrom django.urls import NoReverseMatch, reverse\n\nfrom core.models import ObjectType\nfrom extras.models import Bookmark, ExportTemplate\nfrom utilities.querydict import prepare_cloned_fields\nfrom utilities.views import get_viewname\n\n__all__ = (\n    'add_button',\n    'bookmark_button',\n    'bulk_delete_button',\n    'bulk_edit_button',\n    'clone_button',\n    'delete_button',\n    'edit_button',\n    'export_button',\n    'import_button',\n    'sync_button',\n)\n\nregister = template.Library()\n\n\n#\n# Instance buttons\n#\n\n@register.inclusion_tag('buttons/bookmark.html', takes_context=True)\ndef bookmark_button(context, instance):\n    # Check if this user has already bookmarked the object\n    content_type = ContentType.objects.get_for_model(instance)\n    bookmark = Bookmark.objects.filter(\n        object_type=content_type,\n        object_id=instance.pk,\n        user=context['request'].user\n    ).first()\n\n    # Compile form URL & data\n    if bookmark:\n        form_url = reverse('extras:bookmark_delete', kwargs={'pk': bookmark.pk})\n        form_data = {\n            'confirm': 'true',\n        }\n    else:\n        form_url = reverse('extras:bookmark_add')\n        form_data = {\n            'object_type': content_type.pk,\n            'object_id': instance.pk,\n        }\n\n    return {\n        'bookmark': bookmark,\n        'form_url': form_url,\n        'form_data': form_data,\n        'return_url': instance.get_absolute_url(),\n    }\n\n\n@register.inclusion_tag('buttons/clone.html')\ndef clone_button(instance):\n    url = reverse(get_viewname(instance, 'add'))\n\n    # Populate cloned field values\n    param_string = prepare_cloned_fields(instance).urlencode()\n    if param_string:\n        url = f'{url}?{param_string}'\n    else:\n        url = None\n\n    return {\n        'url': url,\n    }\n\n\n@register.inclusion_tag('buttons/edit.html')\ndef edit_button(instance):\n    viewname = get_viewname(instance, 'edit')\n    url = reverse(viewname, kwargs={'pk': instance.pk})\n\n    return {\n        'url': url,\n    }\n\n\n@register.inclusion_tag('buttons/delete.html')\ndef delete_button(instance):\n    viewname = get_viewname(instance, 'delete')\n    url = reverse(viewname, kwargs={'pk': instance.pk})\n\n    return {\n        'url': url,\n    }\n\n\n@register.inclusion_tag('buttons/sync.html')\ndef sync_button(instance):\n    viewname = get_viewname(instance, 'sync')\n    url = reverse(viewname, kwargs={'pk': instance.pk})\n\n    return {\n        'url': url,\n    }\n\n\n#\n# List buttons\n#\n\n@register.inclusion_tag('buttons/add.html')\ndef add_button(model, action='add'):\n    try:\n        url = reverse(get_viewname(model, action))\n    except NoReverseMatch:\n        url = None\n\n    return {\n        'url': url,\n    }\n\n\n@register.inclusion_tag('buttons/import.html')\ndef import_button(model, action='import'):\n    try:\n        url = reverse(get_viewname(model, action))\n    except NoReverseMatch:\n        url = None\n\n    return {\n        'url': url,\n    }\n\n\n@register.inclusion_tag('buttons/export.html', takes_context=True)\ndef export_button(context, model):\n    object_type = ObjectType.objects.get_for_model(model)\n    user = context['request'].user\n\n    # Determine if the \"all data\" export returns CSV or YAML\n    data_format = 'YAML' if hasattr(object_type.model_class(), 'to_yaml') else 'CSV'\n\n    # Retrieve all export templates for this model\n    export_templates = ExportTemplate.objects.restrict(user, 'view').filter(object_types=object_type)\n\n    return {\n        'perms': context['perms'],\n        'object_type': object_type,\n        'url_params': context['request'].GET.urlencode() if context['request'].GET else '',\n        'export_templates': export_templates,\n        'data_format': data_format,\n    }\n\n\n@register.inclusion_tag('buttons/bulk_edit.html', takes_context=True)\ndef bulk_edit_button(context, model, action='bulk_edit', query_params=None):\n    try:\n        url = reverse(get_viewname(model, action))\n        if query_params:\n            url = f'{url}?{query_params.urlencode()}'\n    except NoReverseMatch:\n        url = None\n\n    return {\n        'htmx_navigation': context.get('htmx_navigation'),\n        'url': url,\n    }\n\n\n@register.inclusion_tag('buttons/bulk_delete.html', takes_context=True)\ndef bulk_delete_button(context, model, action='bulk_delete', query_params=None):\n    try:\n        url = reverse(get_viewname(model, action))\n        if query_params:\n            url = f'{url}?{query_params.urlencode()}'\n    except NoReverseMatch:\n        url = None\n\n    return {\n        'htmx_navigation': context.get('htmx_navigation'),\n        'url': url,\n    }\n", "path": "netbox/utilities/templatetags/buttons.py"}]}