mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-21 03:27:21 -06:00
Move count_related() & dict_to_filter_params() to utilities.query
This commit is contained in:
parent
3b4898adea
commit
ae8df77cc8
@ -6,7 +6,7 @@ from dcim.views import PathTraceView
|
|||||||
from netbox.views import generic
|
from netbox.views import generic
|
||||||
from tenancy.views import ObjectContactsView
|
from tenancy.views import ObjectContactsView
|
||||||
from utilities.forms import ConfirmationForm
|
from utilities.forms import ConfirmationForm
|
||||||
from utilities.utils import count_related
|
from utilities.query import count_related
|
||||||
from utilities.views import register_model_view
|
from utilities.views import register_model_view
|
||||||
from . import filtersets, forms, tables
|
from . import filtersets, forms, tables
|
||||||
from .models import *
|
from .models import *
|
||||||
|
@ -25,7 +25,7 @@ from netbox.views import generic
|
|||||||
from netbox.views.generic.base import BaseObjectView
|
from netbox.views.generic.base import BaseObjectView
|
||||||
from netbox.views.generic.mixins import TableMixin
|
from netbox.views.generic.mixins import TableMixin
|
||||||
from utilities.forms import ConfirmationForm
|
from utilities.forms import ConfirmationForm
|
||||||
from utilities.utils import count_related
|
from utilities.query import count_related
|
||||||
from utilities.views import ContentTypePermissionRequiredMixin, register_model_view
|
from utilities.views import ContentTypePermissionRequiredMixin, register_model_view
|
||||||
from . import filtersets, forms, tables
|
from . import filtersets, forms, tables
|
||||||
from .models import *
|
from .models import *
|
||||||
|
@ -25,8 +25,8 @@ from tenancy.views import ObjectContactsView
|
|||||||
from utilities.forms import ConfirmationForm
|
from utilities.forms import ConfirmationForm
|
||||||
from utilities.paginator import EnhancedPaginator, get_paginate_count
|
from utilities.paginator import EnhancedPaginator, get_paginate_count
|
||||||
from utilities.permissions import get_permission_for_model
|
from utilities.permissions import get_permission_for_model
|
||||||
|
from utilities.query import count_related
|
||||||
from utilities.query_functions import CollateAsChar
|
from utilities.query_functions import CollateAsChar
|
||||||
from utilities.utils import count_related
|
|
||||||
from utilities.views import GetReturnURLMixin, ObjectPermissionRequiredMixin, ViewTab, register_model_view
|
from utilities.views import GetReturnURLMixin, ObjectPermissionRequiredMixin, ViewTab, register_model_view
|
||||||
from virtualization.models import VirtualMachine
|
from virtualization.models import VirtualMachine
|
||||||
from . import filtersets, forms, tables
|
from . import filtersets, forms, tables
|
||||||
|
@ -21,11 +21,11 @@ from netbox.views.generic.mixins import TableMixin
|
|||||||
from utilities.data import shallow_compare_dict
|
from utilities.data import shallow_compare_dict
|
||||||
from utilities.forms import ConfirmationForm, get_field_value
|
from utilities.forms import ConfirmationForm, get_field_value
|
||||||
from utilities.paginator import EnhancedPaginator, get_paginate_count
|
from utilities.paginator import EnhancedPaginator, get_paginate_count
|
||||||
|
from utilities.query import count_related
|
||||||
from utilities.querydict import normalize_querydict
|
from utilities.querydict import normalize_querydict
|
||||||
from utilities.request import copy_safe_request
|
from utilities.request import copy_safe_request
|
||||||
from utilities.rqworker import get_workers_for_queue
|
from utilities.rqworker import get_workers_for_queue
|
||||||
from utilities.templatetags.builtins.filters import render_markdown
|
from utilities.templatetags.builtins.filters import render_markdown
|
||||||
from utilities.utils import count_related
|
|
||||||
from utilities.views import ContentTypePermissionRequiredMixin, get_viewname, register_model_view
|
from utilities.views import ContentTypePermissionRequiredMixin, get_viewname, register_model_view
|
||||||
from . import filtersets, forms, tables
|
from . import filtersets, forms, tables
|
||||||
from .models import *
|
from .models import *
|
||||||
|
@ -3,8 +3,8 @@ from django.db.models import Count, F, OuterRef, Q, Subquery, Value
|
|||||||
from django.db.models.expressions import RawSQL
|
from django.db.models.expressions import RawSQL
|
||||||
from django.db.models.functions import Round
|
from django.db.models.functions import Round
|
||||||
|
|
||||||
|
from utilities.query import count_related
|
||||||
from utilities.querysets import RestrictedQuerySet
|
from utilities.querysets import RestrictedQuerySet
|
||||||
from utilities.utils import count_related
|
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
'ASNRangeQuerySet',
|
'ASNRangeQuerySet',
|
||||||
|
@ -9,8 +9,8 @@ from circuits.models import Provider
|
|||||||
from dcim.filtersets import InterfaceFilterSet
|
from dcim.filtersets import InterfaceFilterSet
|
||||||
from dcim.models import Interface, Site
|
from dcim.models import Interface, Site
|
||||||
from netbox.views import generic
|
from netbox.views import generic
|
||||||
|
from utilities.query import count_related
|
||||||
from utilities.tables import get_table_ordering
|
from utilities.tables import get_table_ordering
|
||||||
from utilities.utils import count_related
|
|
||||||
from utilities.views import ViewTab, register_model_view
|
from utilities.views import ViewTab, register_model_view
|
||||||
from virtualization.filtersets import VMInterfaceFilterSet
|
from virtualization.filtersets import VMInterfaceFilterSet
|
||||||
from virtualization.models import VMInterface
|
from virtualization.models import VMInterface
|
||||||
|
@ -3,7 +3,8 @@ from django.shortcuts import get_object_or_404
|
|||||||
from django.utils.translation import gettext as _
|
from django.utils.translation import gettext as _
|
||||||
|
|
||||||
from netbox.views import generic
|
from netbox.views import generic
|
||||||
from utilities.utils import count_related, get_related_models
|
from utilities.query import count_related
|
||||||
|
from utilities.utils import get_related_models
|
||||||
from utilities.views import register_model_view, ViewTab
|
from utilities.views import register_model_view, ViewTab
|
||||||
from . import filtersets, forms, tables
|
from . import filtersets, forms, tables
|
||||||
from .models import *
|
from .models import *
|
||||||
|
@ -11,8 +11,9 @@ from rest_framework.views import get_view_name as drf_get_view_name
|
|||||||
from extras.constants import HTTP_CONTENT_TYPE_JSON
|
from extras.constants import HTTP_CONTENT_TYPE_JSON
|
||||||
from netbox.api.exceptions import GraphQLTypeNotFound, SerializerNotFound
|
from netbox.api.exceptions import GraphQLTypeNotFound, SerializerNotFound
|
||||||
from netbox.api.fields import RelatedObjectCountField
|
from netbox.api.fields import RelatedObjectCountField
|
||||||
|
from .query import count_related, dict_to_filter_params
|
||||||
from .string import title
|
from .string import title
|
||||||
from .utils import count_related, dict_to_filter_params, dynamic_import
|
from .utils import dynamic_import
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
'get_annotations_for_serializer',
|
'get_annotations_for_serializer',
|
||||||
|
56
netbox/utilities/query.py
Normal file
56
netbox/utilities/query.py
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
from django.db.models import Count, OuterRef, Subquery
|
||||||
|
from django.db.models.functions import Coalesce
|
||||||
|
|
||||||
|
__all__ = (
|
||||||
|
'count_related',
|
||||||
|
'dict_to_filter_params',
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def count_related(model, field):
|
||||||
|
"""
|
||||||
|
Return a Subquery suitable for annotating a child object count.
|
||||||
|
"""
|
||||||
|
subquery = Subquery(
|
||||||
|
model.objects.filter(
|
||||||
|
**{field: OuterRef('pk')}
|
||||||
|
).order_by().values(
|
||||||
|
field
|
||||||
|
).annotate(
|
||||||
|
c=Count('*')
|
||||||
|
).values('c')
|
||||||
|
)
|
||||||
|
|
||||||
|
return Coalesce(subquery, 0)
|
||||||
|
|
||||||
|
|
||||||
|
def dict_to_filter_params(d, prefix=''):
|
||||||
|
"""
|
||||||
|
Translate a dictionary of attributes to a nested set of parameters suitable for QuerySet filtering. For example:
|
||||||
|
|
||||||
|
{
|
||||||
|
"name": "Foo",
|
||||||
|
"rack": {
|
||||||
|
"facility_id": "R101"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Becomes:
|
||||||
|
|
||||||
|
{
|
||||||
|
"name": "Foo",
|
||||||
|
"rack__facility_id": "R101"
|
||||||
|
}
|
||||||
|
|
||||||
|
And can be employed as filter parameters:
|
||||||
|
|
||||||
|
Device.objects.filter(**dict_to_filter(attrs_dict))
|
||||||
|
"""
|
||||||
|
params = {}
|
||||||
|
for key, val in d.items():
|
||||||
|
k = prefix + key
|
||||||
|
if isinstance(val, dict):
|
||||||
|
params.update(dict_to_filter_params(val, k + '__'))
|
||||||
|
else:
|
||||||
|
params[k] = val
|
||||||
|
return params
|
@ -2,8 +2,8 @@ from django.http import QueryDict
|
|||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
|
|
||||||
from utilities.data import deepmerge
|
from utilities.data import deepmerge
|
||||||
|
from utilities.query import dict_to_filter_params
|
||||||
from utilities.querydict import normalize_querydict
|
from utilities.querydict import normalize_querydict
|
||||||
from utilities.utils import dict_to_filter_params
|
|
||||||
|
|
||||||
|
|
||||||
class DictToFilterParamsTest(TestCase):
|
class DictToFilterParamsTest(TestCase):
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
from django.db.models import Count, ManyToOneRel, OuterRef, Subquery
|
from django.db.models import ManyToOneRel
|
||||||
from django.db.models.functions import Coalesce
|
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.utils.timezone import localtime
|
from django.utils.timezone import localtime
|
||||||
|
|
||||||
@ -17,55 +16,6 @@ def dynamic_import(name):
|
|||||||
return mod
|
return mod
|
||||||
|
|
||||||
|
|
||||||
def count_related(model, field):
|
|
||||||
"""
|
|
||||||
Return a Subquery suitable for annotating a child object count.
|
|
||||||
"""
|
|
||||||
subquery = Subquery(
|
|
||||||
model.objects.filter(
|
|
||||||
**{field: OuterRef('pk')}
|
|
||||||
).order_by().values(
|
|
||||||
field
|
|
||||||
).annotate(
|
|
||||||
c=Count('*')
|
|
||||||
).values('c')
|
|
||||||
)
|
|
||||||
|
|
||||||
return Coalesce(subquery, 0)
|
|
||||||
|
|
||||||
|
|
||||||
def dict_to_filter_params(d, prefix=''):
|
|
||||||
"""
|
|
||||||
Translate a dictionary of attributes to a nested set of parameters suitable for QuerySet filtering. For example:
|
|
||||||
|
|
||||||
{
|
|
||||||
"name": "Foo",
|
|
||||||
"rack": {
|
|
||||||
"facility_id": "R101"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Becomes:
|
|
||||||
|
|
||||||
{
|
|
||||||
"name": "Foo",
|
|
||||||
"rack__facility_id": "R101"
|
|
||||||
}
|
|
||||||
|
|
||||||
And can be employed as filter parameters:
|
|
||||||
|
|
||||||
Device.objects.filter(**dict_to_filter(attrs_dict))
|
|
||||||
"""
|
|
||||||
params = {}
|
|
||||||
for key, val in d.items():
|
|
||||||
k = prefix + key
|
|
||||||
if isinstance(val, dict):
|
|
||||||
params.update(dict_to_filter_params(val, k + '__'))
|
|
||||||
else:
|
|
||||||
params[k] = val
|
|
||||||
return params
|
|
||||||
|
|
||||||
|
|
||||||
def content_type_name(ct, include_app=True):
|
def content_type_name(ct, include_app=True):
|
||||||
"""
|
"""
|
||||||
Return a human-friendly ContentType name (e.g. "DCIM > Site").
|
Return a human-friendly ContentType name (e.g. "DCIM > Site").
|
||||||
|
@ -18,8 +18,8 @@ from ipam.tables import InterfaceVLANTable
|
|||||||
from netbox.constants import DEFAULT_ACTION_PERMISSIONS
|
from netbox.constants import DEFAULT_ACTION_PERMISSIONS
|
||||||
from netbox.views import generic
|
from netbox.views import generic
|
||||||
from tenancy.views import ObjectContactsView
|
from tenancy.views import ObjectContactsView
|
||||||
|
from utilities.query import count_related
|
||||||
from utilities.query_functions import CollateAsChar
|
from utilities.query_functions import CollateAsChar
|
||||||
from utilities.utils import count_related
|
|
||||||
from utilities.views import ViewTab, register_model_view
|
from utilities.views import ViewTab, register_model_view
|
||||||
from . import filtersets, forms, tables
|
from . import filtersets, forms, tables
|
||||||
from .models import *
|
from .models import *
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
from ipam.tables import RouteTargetTable
|
from ipam.tables import RouteTargetTable
|
||||||
from netbox.views import generic
|
from netbox.views import generic
|
||||||
from tenancy.views import ObjectContactsView
|
from tenancy.views import ObjectContactsView
|
||||||
from utilities.utils import count_related
|
from utilities.query import count_related
|
||||||
from utilities.views import register_model_view
|
from utilities.views import register_model_view
|
||||||
from . import filtersets, forms, tables
|
from . import filtersets, forms, tables
|
||||||
from .models import *
|
from .models import *
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
from dcim.models import Interface
|
from dcim.models import Interface
|
||||||
from netbox.views import generic
|
from netbox.views import generic
|
||||||
from utilities.utils import count_related
|
from utilities.query import count_related
|
||||||
from utilities.views import register_model_view
|
from utilities.views import register_model_view
|
||||||
from . import filtersets, forms, tables
|
from . import filtersets, forms, tables
|
||||||
from .models import *
|
from .models import *
|
||||||
|
Loading…
Reference in New Issue
Block a user