Skip to content

Instantly share code, notes, and snippets.

@G-kodes
Last active October 26, 2022 09:10
Show Gist options
  • Select an option

  • Save G-kodes/3103a8bbdeb3c80317313f2ef279c685 to your computer and use it in GitHub Desktop.

Select an option

Save G-kodes/3103a8bbdeb3c80317313f2ef279c685 to your computer and use it in GitHub Desktop.
A light-weight implementation of a Django `views.py` approach to parsing the JQuery QueryBuilder object.
from django.db.models import Q
def operator_check(operator: str, filter_base: str, search_value: str) -> Q:
"""Implements Djangos double-underscore filters such as less-than-or-equal.
Args:
rule (dict): A dictionary entry representing an individual JQuery QueryBuilder rule.
filter_base (str): A string representing the base Django model filter string to which we will add the appropriate logic filter.
Returns:
Q: A Q() object representation of the rule, complete with its appropriate logic.
"""
base_dictionary = dict()
if operator == "less":
base_dictionary[filter_base + "__lt"] = search_value
return Q(**base_dictionary)
elif operator == "greater":
base_dictionary[filter_base + "__gt"] = search_value
return Q(**base_dictionary)
elif operator == "less or equal":
base_dictionary[filter_base + "__lte"] = search_value
return Q(**base_dictionary)
elif operator == "greater or equal":
base_dictionary[filter_base + "__gte"] = search_value
return Q(**base_dictionary)
elif operator == "equal":
base_dictionary[filter_base + "__contains"] = search_value
return Q(**base_dictionary)
elif operator == "not_equal":
base_dictionary[filter_base + "__contains"] = search_value
return ~Q(**base_dictionary)
def filter_type_to_q(rule: str) -> Q:
"""Check what type of filter it is and process to Q() object. (Calls another function for -> Q() conversion)
Args:
rule (dict): The individual JQuery QueryBuilder rule as a dictionary
Returns:
Q: A Django Q() object instance representing the JQuery QueryBuilder rule.
"""
if rule["type"] == "integer":
if rule["field"] == "RVIS": # <Select> element
filter_string_base = "gene__rvis_score"
return operator_check(rule["operator"], filter_string_base, 0)
elif rule["field"] == "P-value": # <Select> element
print("ITS A P-VALUE")
filter_string_base = "study_variants__p_value"
return operator_check(rule["operator"], filter_string_base, rule["value"])
elif rule["type"] == "string":
if rule["field"] == "Condition": # <Radio> element
filter_string_base = "study_variants__p_value"
return operator_check(rule["operator"], filter_string_base, rule["value"])
elif rule["field"] == "Gene HPO": # <Text> element
filter_string_base = "gene__gene_hpo"
return operator_check(rule["operator"], filter_string_base, rule["value"])
elif rule["field"] == "Variant consequences": # <Select> element
filter_string_base = "ensembl_vep__consequence_terms"
return operator_check(rule["operator"], filter_string_base, rule["value"])
elif rule["field"] == "Predicted variant effect": # <Radio> element
if rule["value"] == "Pathogenic":
full_query = Q()
for key, value in {
"ensembl_vep__polyphen2_hvar_pred": "P",
"ensembl_vep__sift_prediction": "pathogenic",
"ensembl_vep__sift4g_pred": "P",
"ensembl_vep__fathmm_pred": "P",
}.items():
full_query.add(operator_check(rule["operator"], key, value), Q.OR)
return full_query
elif rule["value"] == "Deleterious":
full_query = Q()
for key, value in {
"mt_vep__query_prediction": "disease causing",
"ensembl_vep__polyphen2_hvar_pred": "D",
"ensembl_vep__sift_prediction": "deleterious",
"ensembl_vep__sift4g_pred": "D",
"ensembl_vep__fathmm_pred": "D",
}.items():
full_query.add(operator_check(rule["operator"], key, value), Q.OR)
return full_query
def tree_explorer(data: dict) -> Q:
"""Generates a full Django Q() object with complex nested AND/OR logic.
Args:
data (dict): A python dictionary of the JQuery QueryBuilder JSON output.
Returns:
Q: A complex Django-compatible Q() object representing the complex query.
Yields:
Iterator[Q]: Q() instance generator for recursive parsing of nested complex queries.
"""
if "type" in data:
# Assume its a valid rule and yield into Q() representation:
yield filter_type_to_q(data)
elif "condition" in data:
# Assume it is a nested group and call this generator recursively,
# constructing this groups complex Q() object in the process:
query = Q()
for rule in data["rules"]:
# Get next() result from generator above
# (bc recursive yields) and process logic:
for rule_instance in tree_explorer(rule):
if data["condition"] == "AND":
query.add(rule_instance, Q.AND)
if data["condition"] == "OR":
query.add(rule_instance, Q.OR)
# Yield the completed, compiled logic for this branch
# of query back up the pipe:
yield query
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment