mirror of
https://github.com/netbox-community/netbox.git
synced 2025-12-18 19:32:24 -06:00
Move count_related() & dict_to_filter_params() to utilities.query
This commit is contained in:
@@ -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 netbox.api.exceptions import GraphQLTypeNotFound, SerializerNotFound
|
||||
from netbox.api.fields import RelatedObjectCountField
|
||||
from .query import count_related, dict_to_filter_params
|
||||
from .string import title
|
||||
from .utils import count_related, dict_to_filter_params, dynamic_import
|
||||
from .utils import dynamic_import
|
||||
|
||||
__all__ = (
|
||||
'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 utilities.data import deepmerge
|
||||
from utilities.query import dict_to_filter_params
|
||||
from utilities.querydict import normalize_querydict
|
||||
from utilities.utils import dict_to_filter_params
|
||||
|
||||
|
||||
class DictToFilterParamsTest(TestCase):
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
from django.db.models import Count, ManyToOneRel, OuterRef, Subquery
|
||||
from django.db.models.functions import Coalesce
|
||||
from django.db.models import ManyToOneRel
|
||||
from django.utils import timezone
|
||||
from django.utils.timezone import localtime
|
||||
|
||||
@@ -17,55 +16,6 @@ def dynamic_import(name):
|
||||
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):
|
||||
"""
|
||||
Return a human-friendly ContentType name (e.g. "DCIM > Site").
|
||||
|
||||
Reference in New Issue
Block a user