Skip to content

Instantly share code, notes, and snippets.

@rickerp
Last active March 9, 2022 00:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rickerp/285d480e228d0d26fe214d25479de343 to your computer and use it in GitHub Desktop.
Save rickerp/285d480e228d0d26fe214d25479de343 to your computer and use it in GitHub Desktop.
Django function to convert a dict to a Q object

Dict to Q object

Django function to convert a dict with filters (allows lookups) to a Q object
Useful when receiving query params in the URL (API)

function dict_to_Q(filters_dict, valid_fields_operations=None, prefix='')

  • filters_dict : dict
    • A dictionary containing the fields and respective filter lookups and values
    • Example: {'tsgte': '2020-10-12', 'tslte': '2021-10-12', ...}
  • valid_fields_operations : dict | optional
    • Allowed fields and respective lookups in filters_dict
    • Default = None : doesn't verify validity (insecure)
    • Example: {'ts': ['gte', 'lte', 'exact'], 'hostname': []}
  • prefix : str | optional
    • Specifies a model to add at the begining of every field in the returned Q object.
    • Defaults to ''.
    • Example:
      >>>dict_to_Q({'ts__gte': '2020-10-12'}, prefix='pc')
      <Q: (AND: ('pc__ts__gte', '2020-10-12'))>

Returns:

  • django.db.models.Q : Q object with the filters of the dictionary

Raises:

  • TypeError: Invalid field name
  • TypeError: Invalid filter lookup for the field

Example:

>>> print(request.GET.dict())
{'ts__gte': ['2020-02-15'], 'ts__lte': ['2020-10-12']}
>>> print(ComputerRecordFilter.get_fields())
OrderedDict([('pc__hostname', ['exact', 'iexact', 'isnull', 'regex', 'iregex', 'contains', 'icontains', 'in', 'gt', 'gte', 'lt', 'lte', 'startswith', 'istartswith', 'endswith', 'iendswith', 'range']), ('ts', ['exact', 'iexact', 'isnull', 'regex', 'iregex', 'contains', 'icontains', 'in', 'gt', 'gte', 'lt', 'lte', 'startswith', 'istartswith', 'endswith', 'iendswith', 'range', 'date', 'year', 'iso_year', 'month', 'day', 'week', 'week_day', 'quarter', 'time', 'hour', 'minute', 'second'])])
>>> dict_to_Q(request.GET.dict(), ComputerRecordFilter.get_fields(), 'computerrecord')
 <Q: (AND: ('computerrecord__ts__gte', '2020-10-12'), ('computerrecord__ts__lte', '2021-02-15'))>
def dict_to_Q(filters_dict, valid_fields_operations=None, prefix=''):
"""
Converts a dictionary to Q filter object
Args:
filters_dict (dict):
Must contain fields, filter lookups and values.
Example: {'ts__gte': '2020-10-12', ...}
valid_fields_operations (dict, optional):
Mapping for valid field names and corresponding filter lookups.
Defaults to None : doesn't verify validity (insecure)
Example: {'ts': ['gte', 'lte', 'exact'], ...}
prefix (str, optional):
Specifies a model to add at the begining of every field.
Defaults to ''.
Example:
>>> dict_to_Q({'ts__gte': '2020-10-12'}, prefix='pc')
<Q: (AND: ('pc__ts__gte', '2020-10-12'))>
Raises:
TypeError: Invalid field name
TypeError: Invalid filter lookup for the field
Returns:
Q: Q object with the filters of the dictionary
"""
ret_dict = dict()
if prefix != '':
prefix += '__'
for filter_field in filters_dict:
filter_sep = filter_field.split('__')
fname = filter_sep[0]
lookup = filter_sep[1] if len(filter_sep) == 2 else 'exact'
if valid_fields_operations:
if fname not in valid_fields_operations:
raise TypeError(f"Invalid field name: '{fname}'")
if lookup not in valid_fields_operations.get(fname):
raise TypeError(f"There is no valid operation '{lookup}' for the '{fname}' field")
ret_dict[prefix + filter_field] = filters_dict.get(filter_field)
return Q(**ret_dict)
@rickerp
Copy link
Author

rickerp commented Oct 19, 2020

Example:

>>> print(request.GET)
<QueryDict: {'ts__gte': ['2020-02-15'], 'ts__lte': ['2020-10-12']}>
>>> dict_to_Q(request.GET.dict(), ComputerRecordFilter.get_fields(), 'computerrecord')
 <Q: (AND: ('computerrecord__ts__gte', '2020-10-12'), ('computerrecord__ts__lte', '2021-02-15'))>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment