2023-11-16 12:02:32 -05:00
|
|
|
from django.db.models import Count, ManyToOneRel, OuterRef, Subquery
|
2020-12-17 14:45:50 -05:00
|
|
|
from django.db.models.functions import Coalesce
|
2023-01-06 09:42:13 -05:00
|
|
|
from django.utils import timezone
|
|
|
|
from django.utils.timezone import localtime
|
2018-02-02 13:32:16 -05:00
|
|
|
|
2024-03-21 12:06:28 -04:00
|
|
|
from .string import title
|
2022-11-02 16:26:26 -04:00
|
|
|
|
|
|
|
|
2018-05-30 11:19:10 -04:00
|
|
|
def dynamic_import(name):
|
|
|
|
"""
|
|
|
|
Dynamically import a class from an absolute path string
|
|
|
|
"""
|
|
|
|
components = name.split('.')
|
|
|
|
mod = __import__(components[0])
|
|
|
|
for comp in components[1:]:
|
|
|
|
mod = getattr(mod, comp)
|
|
|
|
return mod
|
2018-06-22 14:00:23 -04:00
|
|
|
|
|
|
|
|
2020-12-17 14:47:49 -05:00
|
|
|
def count_related(model, field):
|
2019-04-19 16:09:22 -04:00
|
|
|
"""
|
|
|
|
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')
|
|
|
|
)
|
|
|
|
|
2020-12-17 14:45:50 -05:00
|
|
|
return Coalesce(subquery, 0)
|
2019-04-19 16:09:22 -04:00
|
|
|
|
|
|
|
|
2019-04-16 18:02:52 -04:00
|
|
|
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
|
|
|
|
|
|
|
|
|
2022-11-02 16:26:26 -04:00
|
|
|
def content_type_name(ct, include_app=True):
|
2021-04-09 09:43:35 -04:00
|
|
|
"""
|
2021-11-17 11:02:22 -05:00
|
|
|
Return a human-friendly ContentType name (e.g. "DCIM > Site").
|
2021-04-09 09:43:35 -04:00
|
|
|
"""
|
2021-09-01 12:55:25 -04:00
|
|
|
try:
|
2021-11-17 11:02:22 -05:00
|
|
|
meta = ct.model_class()._meta
|
2022-11-02 16:26:26 -04:00
|
|
|
app_label = title(meta.app_config.verbose_name)
|
|
|
|
model_name = title(meta.verbose_name)
|
|
|
|
if include_app:
|
|
|
|
return f'{app_label} > {model_name}'
|
|
|
|
return model_name
|
2021-09-01 12:55:25 -04:00
|
|
|
except AttributeError:
|
|
|
|
# Model no longer exists
|
2021-11-17 11:02:22 -05:00
|
|
|
return f'{ct.app_label} > {ct.model}'
|
|
|
|
|
|
|
|
|
|
|
|
def content_type_identifier(ct):
|
|
|
|
"""
|
|
|
|
Return a "raw" ContentType identifier string suitable for bulk import/export (e.g. "dcim.site").
|
|
|
|
"""
|
|
|
|
return f'{ct.app_label}.{ct.model}'
|
2021-04-09 09:43:35 -04:00
|
|
|
|
|
|
|
|
2023-01-06 09:42:13 -05:00
|
|
|
def local_now():
|
|
|
|
"""
|
|
|
|
Return the current date & time in the system timezone.
|
|
|
|
"""
|
|
|
|
return localtime(timezone.now())
|
2023-11-16 12:02:32 -05:00
|
|
|
|
|
|
|
|
|
|
|
def get_related_models(model, ordered=True):
|
|
|
|
"""
|
|
|
|
Return a list of all models which have a ForeignKey to the given model and the name of the field. For example,
|
|
|
|
`get_related_models(Tenant)` will return all models which have a ForeignKey relationship to Tenant.
|
|
|
|
"""
|
|
|
|
related_models = [
|
|
|
|
(field.related_model, field.remote_field.name)
|
|
|
|
for field in model._meta.related_objects
|
|
|
|
if type(field) is ManyToOneRel
|
|
|
|
]
|
|
|
|
|
|
|
|
if ordered:
|
2023-12-01 11:23:38 -05:00
|
|
|
return sorted(related_models, key=lambda x: x[0]._meta.verbose_name.lower())
|
2023-11-16 12:02:32 -05:00
|
|
|
|
|
|
|
return related_models
|