mirror of
https://github.com/netbox-community/netbox.git
synced 2025-12-13 03:49:36 -06:00
Address PR feedback: Move FORM_FIELD_LOOKUPS to module-level constant
Extracts the field type to lookup mappings from FilterModifierMixin class attribute to a module-level constant for better reusability.
This commit is contained in:
parent
05e1317f5e
commit
ac74d9f9be
@ -13,82 +13,10 @@ __all__ = (
|
|||||||
'CheckLastUpdatedMixin',
|
'CheckLastUpdatedMixin',
|
||||||
'DistanceValidationMixin',
|
'DistanceValidationMixin',
|
||||||
'FilterModifierMixin',
|
'FilterModifierMixin',
|
||||||
|
'FORM_FIELD_LOOKUPS',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class BackgroundJobMixin(forms.Form):
|
|
||||||
background_job = forms.BooleanField(
|
|
||||||
label=_('Background job'),
|
|
||||||
help_text=_("Execute this task via a background job"),
|
|
||||||
required=False,
|
|
||||||
)
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
super().__init__(*args, **kwargs)
|
|
||||||
|
|
||||||
# Declare background_job a meta field
|
|
||||||
if hasattr(self, 'meta_fields'):
|
|
||||||
self.meta_fields.append('background_job')
|
|
||||||
else:
|
|
||||||
self.meta_fields = ['background_job']
|
|
||||||
|
|
||||||
|
|
||||||
class CheckLastUpdatedMixin(forms.Form):
|
|
||||||
"""
|
|
||||||
Checks whether the object being saved has been updated since the form was initialized. If so, validation fails.
|
|
||||||
This prevents a user from inadvertently overwriting any changes made to the object between when the form was
|
|
||||||
initialized and when it was submitted.
|
|
||||||
|
|
||||||
This validation does not apply to newly created objects, or if the `_init_time` field is not present in the form
|
|
||||||
data.
|
|
||||||
"""
|
|
||||||
_init_time = forms.DecimalField(
|
|
||||||
initial=time.time,
|
|
||||||
required=False,
|
|
||||||
widget=forms.HiddenInput()
|
|
||||||
)
|
|
||||||
|
|
||||||
def clean(self):
|
|
||||||
super().clean()
|
|
||||||
|
|
||||||
# Skip for absent or newly created instances
|
|
||||||
if not self.instance or not self.instance.pk:
|
|
||||||
return
|
|
||||||
|
|
||||||
# Skip if a form init time has not been specified
|
|
||||||
if not (form_init_time := self.cleaned_data.get('_init_time')):
|
|
||||||
return
|
|
||||||
|
|
||||||
# Skip if the object does not have a last_updated value
|
|
||||||
if not (last_updated := getattr(self.instance, 'last_updated', None)):
|
|
||||||
return
|
|
||||||
|
|
||||||
# Check that the submitted initialization time is not earlier than the object's modification time
|
|
||||||
if form_init_time < last_updated.timestamp():
|
|
||||||
raise forms.ValidationError(_(
|
|
||||||
"This object has been modified since the form was rendered. Please consult the object's change "
|
|
||||||
"log for details."
|
|
||||||
))
|
|
||||||
|
|
||||||
|
|
||||||
class DistanceValidationMixin(forms.Form):
|
|
||||||
distance = forms.DecimalField(
|
|
||||||
required=False,
|
|
||||||
validators=[
|
|
||||||
MinValueValidator(Decimal(0)),
|
|
||||||
MaxValueValidator(Decimal(100000)),
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class FilterModifierMixin:
|
|
||||||
"""
|
|
||||||
Mixin that enhances filter form fields with lookup modifier dropdowns.
|
|
||||||
|
|
||||||
Automatically detects fields that could benefit from multiple lookup options
|
|
||||||
and wraps their widgets with FilterModifierWidget.
|
|
||||||
"""
|
|
||||||
|
|
||||||
# Mapping of form field types to their supported lookups
|
# Mapping of form field types to their supported lookups
|
||||||
FORM_FIELD_LOOKUPS = {
|
FORM_FIELD_LOOKUPS = {
|
||||||
forms.CharField: [
|
forms.CharField: [
|
||||||
@ -165,6 +93,80 @@ class FilterModifierMixin:
|
|||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class BackgroundJobMixin(forms.Form):
|
||||||
|
background_job = forms.BooleanField(
|
||||||
|
label=_('Background job'),
|
||||||
|
help_text=_("Execute this task via a background job"),
|
||||||
|
required=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
# Declare background_job a meta field
|
||||||
|
if hasattr(self, 'meta_fields'):
|
||||||
|
self.meta_fields.append('background_job')
|
||||||
|
else:
|
||||||
|
self.meta_fields = ['background_job']
|
||||||
|
|
||||||
|
|
||||||
|
class CheckLastUpdatedMixin(forms.Form):
|
||||||
|
"""
|
||||||
|
Checks whether the object being saved has been updated since the form was initialized. If so, validation fails.
|
||||||
|
This prevents a user from inadvertently overwriting any changes made to the object between when the form was
|
||||||
|
initialized and when it was submitted.
|
||||||
|
|
||||||
|
This validation does not apply to newly created objects, or if the `_init_time` field is not present in the form
|
||||||
|
data.
|
||||||
|
"""
|
||||||
|
_init_time = forms.DecimalField(
|
||||||
|
initial=time.time,
|
||||||
|
required=False,
|
||||||
|
widget=forms.HiddenInput()
|
||||||
|
)
|
||||||
|
|
||||||
|
def clean(self):
|
||||||
|
super().clean()
|
||||||
|
|
||||||
|
# Skip for absent or newly created instances
|
||||||
|
if not self.instance or not self.instance.pk:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Skip if a form init time has not been specified
|
||||||
|
if not (form_init_time := self.cleaned_data.get('_init_time')):
|
||||||
|
return
|
||||||
|
|
||||||
|
# Skip if the object does not have a last_updated value
|
||||||
|
if not (last_updated := getattr(self.instance, 'last_updated', None)):
|
||||||
|
return
|
||||||
|
|
||||||
|
# Check that the submitted initialization time is not earlier than the object's modification time
|
||||||
|
if form_init_time < last_updated.timestamp():
|
||||||
|
raise forms.ValidationError(_(
|
||||||
|
"This object has been modified since the form was rendered. Please consult the object's change "
|
||||||
|
"log for details."
|
||||||
|
))
|
||||||
|
|
||||||
|
|
||||||
|
class DistanceValidationMixin(forms.Form):
|
||||||
|
distance = forms.DecimalField(
|
||||||
|
required=False,
|
||||||
|
validators=[
|
||||||
|
MinValueValidator(Decimal(0)),
|
||||||
|
MaxValueValidator(Decimal(100000)),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class FilterModifierMixin:
|
||||||
|
"""
|
||||||
|
Mixin that enhances filter form fields with lookup modifier dropdowns.
|
||||||
|
|
||||||
|
Automatically detects fields that could benefit from multiple lookup options
|
||||||
|
and wraps their widgets with FilterModifierWidget.
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self._enhance_fields_with_modifiers()
|
self._enhance_fields_with_modifiers()
|
||||||
@ -217,8 +219,8 @@ class FilterModifierMixin:
|
|||||||
"""Determine the available lookup choices for a given field."""
|
"""Determine the available lookup choices for a given field."""
|
||||||
# Walk up the MRO to find a known field type
|
# Walk up the MRO to find a known field type
|
||||||
for field_class in field.__class__.__mro__:
|
for field_class in field.__class__.__mro__:
|
||||||
if field_class in self.FORM_FIELD_LOOKUPS:
|
if field_class in FORM_FIELD_LOOKUPS:
|
||||||
return self.FORM_FIELD_LOOKUPS[field_class]
|
return FORM_FIELD_LOOKUPS[field_class]
|
||||||
|
|
||||||
# Unknown field type - return single exact option (no enhancement)
|
# Unknown field type - return single exact option (no enhancement)
|
||||||
return [('exact', _('Is'))]
|
return [('exact', _('Is'))]
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user