Initial commit
This commit is contained in:
commit
4ff9eac274
45 files changed
+2911
No files matched your search
@@ -0,0 +1,104 @@
|
||||
"""Selectors resolve a specification into a queryset of matching NetBox objects."""
|
||||
|
||||
import importlib
|
||||
|
||||
from django.db.models import Q
|
||||
|
||||
from .registry import register_selector
|
||||
|
||||
|
||||
def _get_filterset_for_model(model):
|
||||
"""Look up a model's FilterSet by convention: {app_label}.filtersets.{ModelName}FilterSet."""
|
||||
app_label = model._meta.app_label
|
||||
model_name = model._meta.model_name
|
||||
class_name = f"{model.__name__}FilterSet"
|
||||
try:
|
||||
module = importlib.import_module(f"{app_label}.filtersets")
|
||||
return getattr(module, class_name, None)
|
||||
except (ImportError, AttributeError):
|
||||
return None
|
||||
|
||||
|
||||
@register_selector("netbox_filter")
|
||||
class NetBoxFilterSelector:
|
||||
"""Select objects by applying NetBox filter parameters.
|
||||
|
||||
Spec shape::
|
||||
{"type": "netbox_filter", "filters": {"role": "router", "site__in": ["hq"]}}
|
||||
"""
|
||||
|
||||
def __init__(self, spec):
|
||||
self.spec = spec
|
||||
self.filters = spec.get("filters", {})
|
||||
|
||||
def resolve(self, context, model):
|
||||
qs = model.objects.all()
|
||||
filterset_cls = _get_filterset_for_model(model)
|
||||
if filterset_cls is not None:
|
||||
fs = filterset_cls(self.filters, queryset=qs, request=None)
|
||||
qs = fs.qs
|
||||
else:
|
||||
qs = qs.filter(**self._build_q(self.filters))
|
||||
return qs
|
||||
|
||||
@staticmethod
|
||||
def _build_q(filters):
|
||||
"""Best-effort: turn the filter dict into ORM kwargs (no fancy lookups)."""
|
||||
return {k: v for k, v in filters.items()}
|
||||
|
||||
|
||||
@register_selector("reference")
|
||||
class ReferenceSelector:
|
||||
"""Select a single object via a dotted context path.
|
||||
|
||||
Spec shape::
|
||||
{"type": "reference", "path": "parent.site"}
|
||||
"""
|
||||
|
||||
def __init__(self, spec):
|
||||
self.spec = spec
|
||||
self.path = spec.get("path")
|
||||
|
||||
def resolve(self, context, model):
|
||||
obj = context.resolve_path(self.path)
|
||||
if obj is None:
|
||||
return model.objects.none()
|
||||
if isinstance(obj, (list, tuple)):
|
||||
return model.objects.filter(pk__in=[o.pk for o in obj])
|
||||
return model.objects.filter(pk=obj.pk)
|
||||
|
||||
|
||||
@register_selector("prefix")
|
||||
class PrefixSelector:
|
||||
"""Select ipam.Prefix objects by filter or context reference.
|
||||
|
||||
Spec shape (filter)::
|
||||
{"type": "prefix", "filters": {"site": "hq", "tag": "mgmt"}}
|
||||
|
||||
Spec shape (reference)::
|
||||
{"type": "prefix", "path": "parent.site.management_prefix"}
|
||||
"""
|
||||
|
||||
def __init__(self, spec):
|
||||
self.spec = spec
|
||||
self.filters = spec.get("filters")
|
||||
self.path = spec.get("path")
|
||||
|
||||
def resolve(self, context, model):
|
||||
from ipam.models import Prefix
|
||||
|
||||
if self.path:
|
||||
obj = context.resolve_path(self.path)
|
||||
if obj is None:
|
||||
return Prefix.objects.none()
|
||||
return Prefix.objects.filter(pk=obj.pk)
|
||||
|
||||
if self.filters is not None:
|
||||
filterset_cls = _get_filterset_for_model(Prefix)
|
||||
qs = Prefix.objects.all()
|
||||
if filterset_cls is not None:
|
||||
fs = filterset_cls(self.filters, queryset=qs, request=None)
|
||||
return fs.qs
|
||||
return qs.filter(**self.filters)
|
||||
|
||||
return Prefix.objects.none()
|
||||
Reference in new issue
Block a user