|
|
@@ -1,12 +1,9 @@
|
|
|
import datetime
|
|
|
import decimal
|
|
|
-import json
|
|
|
from itertools import count, groupby
|
|
|
from urllib.parse import urlencode
|
|
|
|
|
|
import nh3
|
|
|
-from django.contrib.contenttypes.models import ContentType
|
|
|
-from django.core import serializers
|
|
|
from django.db.models import Count, ManyToOneRel, OuterRef, Subquery
|
|
|
from django.db.models.functions import Coalesce
|
|
|
from django.http import QueryDict
|
|
|
@@ -14,9 +11,7 @@ from django.utils import timezone
|
|
|
from django.utils.datastructures import MultiValueDict
|
|
|
from django.utils.timezone import localtime
|
|
|
from jinja2.sandbox import SandboxedEnvironment
|
|
|
-from mptt.models import MPTTModel
|
|
|
|
|
|
-from extras.utils import is_taggable
|
|
|
from netbox.config import get_config
|
|
|
from .constants import HTML_ALLOWED_ATTRIBUTES, HTML_ALLOWED_TAGS
|
|
|
from .string import title
|
|
|
@@ -96,69 +91,6 @@ def count_related(model, field):
|
|
|
return Coalesce(subquery, 0)
|
|
|
|
|
|
|
|
|
-def serialize_object(obj, resolve_tags=True, extra=None, exclude=None):
|
|
|
- """
|
|
|
- Return a generic JSON representation of an object using Django's built-in serializer. (This is used for things like
|
|
|
- change logging, not the REST API.) Optionally include a dictionary to supplement the object data. A list of keys
|
|
|
- can be provided to exclude them from the returned dictionary. Private fields (prefaced with an underscore) are
|
|
|
- implicitly excluded.
|
|
|
-
|
|
|
- Args:
|
|
|
- obj: The object to serialize
|
|
|
- resolve_tags: If true, any assigned tags will be represented by their names
|
|
|
- extra: Any additional data to include in the serialized output. Keys provided in this mapping will
|
|
|
- override object attributes.
|
|
|
- exclude: An iterable of attributes to exclude from the serialized output
|
|
|
- """
|
|
|
- json_str = serializers.serialize('json', [obj])
|
|
|
- data = json.loads(json_str)[0]['fields']
|
|
|
- exclude = exclude or []
|
|
|
-
|
|
|
- # Exclude any MPTTModel fields
|
|
|
- if issubclass(obj.__class__, MPTTModel):
|
|
|
- for field in ['level', 'lft', 'rght', 'tree_id']:
|
|
|
- data.pop(field)
|
|
|
-
|
|
|
- # Include custom_field_data as "custom_fields"
|
|
|
- if hasattr(obj, 'custom_field_data'):
|
|
|
- data['custom_fields'] = data.pop('custom_field_data')
|
|
|
-
|
|
|
- # Resolve any assigned tags to their names. Check for tags cached on the instance;
|
|
|
- # fall back to using the manager.
|
|
|
- if resolve_tags and is_taggable(obj):
|
|
|
- tags = getattr(obj, '_tags', None) or obj.tags.all()
|
|
|
- data['tags'] = sorted([tag.name for tag in tags])
|
|
|
-
|
|
|
- # Skip excluded and private (prefixes with an underscore) attributes
|
|
|
- for key in list(data.keys()):
|
|
|
- if key in exclude or (isinstance(key, str) and key.startswith('_')):
|
|
|
- data.pop(key)
|
|
|
-
|
|
|
- # Append any extra data
|
|
|
- if extra is not None:
|
|
|
- data.update(extra)
|
|
|
-
|
|
|
- return data
|
|
|
-
|
|
|
-
|
|
|
-def deserialize_object(model, fields, pk=None):
|
|
|
- """
|
|
|
- Instantiate an object from the given model and field data. Functions as
|
|
|
- the complement to serialize_object().
|
|
|
- """
|
|
|
- content_type = ContentType.objects.get_for_model(model)
|
|
|
- if 'custom_fields' in fields:
|
|
|
- fields['custom_field_data'] = fields.pop('custom_fields')
|
|
|
- data = {
|
|
|
- 'model': '.'.join(content_type.natural_key()),
|
|
|
- 'pk': pk,
|
|
|
- 'fields': fields,
|
|
|
- }
|
|
|
- instance = list(serializers.deserialize('python', [data]))[0]
|
|
|
-
|
|
|
- return instance
|
|
|
-
|
|
|
-
|
|
|
def dict_to_filter_params(d, prefix=''):
|
|
|
"""
|
|
|
Translate a dictionary of attributes to a nested set of parameters suitable for QuerySet filtering. For example:
|