from urllib.parse import urlencode from django.http import QueryDict from django.utils.datastructures import MultiValueDict __all__ = ( 'dict_to_querydict', 'normalize_querydict', 'prepare_cloned_fields', ) def dict_to_querydict(d, mutable=True): """ Create a QueryDict instance from a regular Python dictionary. """ qd = QueryDict(mutable=True) for k, v in d.items(): item = MultiValueDict({k: v}) if isinstance(v, (list, tuple, set)) else {k: v} qd.update(item) if not mutable: qd._mutable = False return qd def normalize_querydict(querydict): """ Convert a QueryDict to a normal, mutable dictionary, preserving list values. For example, QueryDict('foo=1&bar=2&bar=3&baz=') becomes: {'foo': '1', 'bar': ['2', '3'], 'baz': ''} This function is necessary because QueryDict does not provide any built-in mechanism which preserves multiple values. """ return { k: v if len(v) > 1 else v[0] for k, v in querydict.lists() } def prepare_cloned_fields(instance): """ Generate a QueryDict comprising attributes from an object's clone() method. """ # Generate the clone attributes from the instance if not hasattr(instance, 'clone'): return QueryDict(mutable=True) attrs = instance.clone() # Prepare QueryDict parameters params = [] for key, value in attrs.items(): if type(value) in (list, tuple): params.extend([(key, v) for v in value]) elif value not in (False, None): params.append((key, value)) else: params.append((key, '')) # Return a QueryDict with the parameters return QueryDict(urlencode(params), mutable=True)