mirror of
https://github.com/netbox-community/netbox.git
synced 2025-09-06 14:23:36 -06:00
#20048 review feedback
This commit is contained in:
parent
025afb6b1c
commit
0f53bfdc19
@ -11,7 +11,7 @@ from django.conf import settings
|
|||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
from django.db.models import Model
|
from django.db.models import Model
|
||||||
from django.template.loader import render_to_string
|
from django.template.loader import render_to_string
|
||||||
from django.urls import NoReverseMatch, resolve, reverse
|
from django.urls import NoReverseMatch, resolve
|
||||||
from django.utils.translation import gettext as _
|
from django.utils.translation import gettext as _
|
||||||
|
|
||||||
from core.models import ObjectType
|
from core.models import ObjectType
|
||||||
@ -53,9 +53,9 @@ def object_list_widget_supports_model(model: Model) -> bool:
|
|||||||
"""
|
"""
|
||||||
def can_resolve_model_list_view(model: Model) -> bool:
|
def can_resolve_model_list_view(model: Model) -> bool:
|
||||||
try:
|
try:
|
||||||
reverse(get_action_url(model, action='list'))
|
get_action_url(model, action='list')
|
||||||
return True
|
return True
|
||||||
except Exception:
|
except NoReverseMatch:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
tests = [
|
tests = [
|
||||||
|
@ -45,4 +45,4 @@ class ObjectListWidgetTests(TestCase):
|
|||||||
mock_request = Request()
|
mock_request = Request()
|
||||||
widget = ObjectListWidget(id='2829fd9b-5dee-4c9a-81f2-5bd84c350a27', **config)
|
widget = ObjectListWidget(id='2829fd9b-5dee-4c9a-81f2-5bd84c350a27', **config)
|
||||||
rendered = widget.render(mock_request)
|
rendered = widget.render(mock_request)
|
||||||
self.assertTrue('Unable to load content. Invalid list viewname for:' in rendered)
|
self.assertTrue('Unable to load content. Could not resolve list URL for:' in rendered)
|
||||||
|
@ -285,7 +285,7 @@ class ActionsColumn(tables.Column):
|
|||||||
for idx, (action, attrs) in enumerate(self.actions.items()):
|
for idx, (action, attrs) in enumerate(self.actions.items()):
|
||||||
permission = get_permission_for_model(model, attrs.permission)
|
permission = get_permission_for_model(model, attrs.permission)
|
||||||
if attrs.permission is None or user.has_perm(permission):
|
if attrs.permission is None or user.has_perm(permission):
|
||||||
url = get_action_url(record, action=action, kwargs={'pk': record.pk})
|
url = get_action_url(model, action=action, kwargs={'pk': record.pk})
|
||||||
|
|
||||||
# Render a separate button if a) only one action exists, or b) if split_actions is True
|
# Render a separate button if a) only one action exists, or b) if split_actions is True
|
||||||
if len(self.actions) == 1 or (self.split_actions and idx == 0):
|
if len(self.actions) == 1 or (self.split_actions and idx == 0):
|
||||||
|
@ -7,6 +7,6 @@
|
|||||||
</div>
|
</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="text-danger text-center">
|
<div class="text-danger text-center">
|
||||||
<i class="mdi mdi-alert"></i> {% trans "Unable to load content. Invalid list viewname for:" %} <span class="font-monospace">{{ model_name }}</span>
|
<i class="mdi mdi-alert"></i> {% trans "Unable to load content. Could not resolve list URL for:" %} <span class="font-monospace">{{ model_name }}</span>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -12,6 +12,7 @@ from utilities.views import get_viewname, get_action_url
|
|||||||
from netbox.settings import DISK_BASE_UNIT, RAM_BASE_UNIT
|
from netbox.settings import DISK_BASE_UNIT, RAM_BASE_UNIT
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
|
'action_url',
|
||||||
'applied_filters',
|
'applied_filters',
|
||||||
'as_range',
|
'as_range',
|
||||||
'divide',
|
'divide',
|
||||||
@ -64,6 +65,59 @@ def validated_viewname(model, action):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
class ActionURLNode(template.Node):
|
||||||
|
"""Template node for the {% action_url %} template tag."""
|
||||||
|
|
||||||
|
child_nodelists = ()
|
||||||
|
|
||||||
|
def __init__(self, model, action, kwargs, asvar=None):
|
||||||
|
self.model = model
|
||||||
|
self.action = action
|
||||||
|
self.kwargs = kwargs
|
||||||
|
self.asvar = asvar
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return (
|
||||||
|
f"<{self.__class__.__qualname__} "
|
||||||
|
f"model='{self.model}' "
|
||||||
|
f"action='{self.action}' "
|
||||||
|
f"kwargs={repr(self.kwargs)} "
|
||||||
|
f"as={repr(self.asvar)}>"
|
||||||
|
)
|
||||||
|
|
||||||
|
def render(self, context):
|
||||||
|
"""
|
||||||
|
Render the action URL node.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
context: The template context
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The resolved URL or empty string if using 'as' syntax
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
NoReverseMatch: If the URL cannot be resolved and not using 'as' syntax
|
||||||
|
"""
|
||||||
|
# Resolve model and kwargs from context
|
||||||
|
model = self.model.resolve(context)
|
||||||
|
kwargs = {k: v.resolve(context) for k, v in self.kwargs.items()}
|
||||||
|
|
||||||
|
# Get the action URL using the utility function
|
||||||
|
try:
|
||||||
|
url = get_action_url(model, action=self.action, kwargs=kwargs)
|
||||||
|
except NoReverseMatch:
|
||||||
|
if self.asvar is None:
|
||||||
|
raise
|
||||||
|
url = ""
|
||||||
|
|
||||||
|
# Handle variable assignment or return escaped URL
|
||||||
|
if self.asvar:
|
||||||
|
context[self.asvar] = url
|
||||||
|
return ""
|
||||||
|
|
||||||
|
return conditional_escape(url) if context.autoescape else url
|
||||||
|
|
||||||
|
|
||||||
@register.tag
|
@register.tag
|
||||||
def action_url(parser, token):
|
def action_url(parser, token):
|
||||||
"""
|
"""
|
||||||
@ -82,7 +136,7 @@ def action_url(parser, token):
|
|||||||
|
|
||||||
{% action_url model "action_name" pk=object.pk as variable_name %}
|
{% action_url model "action_name" pk=object.pk as variable_name %}
|
||||||
|
|
||||||
The first argument is a model instance. The second argument is the action name.
|
The first argument is a model or instance. The second argument is the action name.
|
||||||
Additional keyword arguments can be passed for URL parameters.
|
Additional keyword arguments can be passed for URL parameters.
|
||||||
|
|
||||||
For example, if you have a Device model and want to link to its edit action::
|
For example, if you have a Device model and want to link to its edit action::
|
||||||
@ -99,59 +153,6 @@ def action_url(parser, token):
|
|||||||
|
|
||||||
{% action_url device "edit" as edit_url %}
|
{% action_url device "edit" as edit_url %}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
class ActionURLNode(template.Node):
|
|
||||||
"""Template node for the {% action_url %} template tag."""
|
|
||||||
|
|
||||||
child_nodelists = ()
|
|
||||||
|
|
||||||
def __init__(self, model, action, kwargs, asvar=None):
|
|
||||||
self.model = model
|
|
||||||
self.action = action
|
|
||||||
self.kwargs = kwargs
|
|
||||||
self.asvar = asvar
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
return (
|
|
||||||
f"<{self.__class__.__qualname__} "
|
|
||||||
f"model='{self.model}' "
|
|
||||||
f"action='{self.action}' "
|
|
||||||
f"kwargs={repr(self.kwargs)} "
|
|
||||||
f"as={repr(self.asvar)}>"
|
|
||||||
)
|
|
||||||
|
|
||||||
def render(self, context):
|
|
||||||
"""
|
|
||||||
Render the action URL node.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
context: The template context
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
The resolved URL or empty string if using 'as' syntax
|
|
||||||
|
|
||||||
Raises:
|
|
||||||
NoReverseMatch: If the URL cannot be resolved and not using 'as' syntax
|
|
||||||
"""
|
|
||||||
# Resolve model and kwargs from context
|
|
||||||
model = self.model.resolve(context)
|
|
||||||
kwargs = {k: v.resolve(context) for k, v in self.kwargs.items()}
|
|
||||||
|
|
||||||
# Get the action URL using the utility function
|
|
||||||
try:
|
|
||||||
url = get_action_url(model, action=self.action, kwargs=kwargs)
|
|
||||||
except NoReverseMatch:
|
|
||||||
if self.asvar is None:
|
|
||||||
raise
|
|
||||||
url = ""
|
|
||||||
|
|
||||||
# Handle variable assignment or return escaped URL
|
|
||||||
if self.asvar:
|
|
||||||
context[self.asvar] = url
|
|
||||||
return ""
|
|
||||||
|
|
||||||
return conditional_escape(url) if context.autoescape else url
|
|
||||||
|
|
||||||
# Parse the token contents
|
# Parse the token contents
|
||||||
bits = token.split_contents()
|
bits = token.split_contents()
|
||||||
if len(bits) < 3:
|
if len(bits) < 3:
|
||||||
|
@ -20,6 +20,7 @@ __all__ = (
|
|||||||
'GetReturnURLMixin',
|
'GetReturnURLMixin',
|
||||||
'ObjectPermissionRequiredMixin',
|
'ObjectPermissionRequiredMixin',
|
||||||
'ViewTab',
|
'ViewTab',
|
||||||
|
'get_action_url',
|
||||||
'get_viewname',
|
'get_viewname',
|
||||||
'register_model_view',
|
'register_model_view',
|
||||||
)
|
)
|
||||||
@ -284,12 +285,13 @@ def get_viewname(model, action=None, rest_api=False):
|
|||||||
|
|
||||||
def get_action_url(model, action=None, rest_api=False, kwargs=None):
|
def get_action_url(model, action=None, rest_api=False, kwargs=None):
|
||||||
"""
|
"""
|
||||||
Return the url for the given model and action, if valid.
|
Return the URL for the given model and action, if valid; otherwise raise NoReverseMatch.
|
||||||
|
Will defer to _get_action_url() on the model if it exists.
|
||||||
|
|
||||||
:param model: The model or instance to which the view applies
|
:param model: The model or instance to which the URL belongs
|
||||||
:param action: A string indicating the desired action (if any); e.g. "add" or "list"
|
:param action: A string indicating the desired action (if any); e.g. "add" or "list"
|
||||||
:param rest_api: A boolean indicating whether this is a REST API view
|
:param rest_api: A boolean indicating whether this is a REST API action
|
||||||
:param kwargs: A dictionary of keyword arguments for the view to include when registering its URL path (optional).
|
:param kwargs: A dictionary of keyword arguments for the view to include when resolving its URL path (optional)
|
||||||
"""
|
"""
|
||||||
if hasattr(model, '_get_action_url'):
|
if hasattr(model, '_get_action_url'):
|
||||||
return model._get_action_url(action, rest_api, kwargs)
|
return model._get_action_url(action, rest_api, kwargs)
|
||||||
|
Loading…
Reference in New Issue
Block a user