From ad1c17a255467f856cb8ad321bf4f6e0f130c7d9 Mon Sep 17 00:00:00 2001 From: Aaron Kable Date: Thu, 8 Jan 2026 20:11:40 +0800 Subject: [PATCH] parmas to dict --- allianceauth/framework/datatables.py | 129 +++++++++++---------------- 1 file changed, 50 insertions(+), 79 deletions(-) diff --git a/allianceauth/framework/datatables.py b/allianceauth/framework/datatables.py index 56c1fa3d..9b6b42ba 100644 --- a/allianceauth/framework/datatables.py +++ b/allianceauth/framework/datatables.py @@ -13,81 +13,56 @@ from allianceauth.services.hooks import get_extension_logger logger = get_extension_logger(__name__) + +class nested_param_dict(dict): + def __setitem__(self, item, value): + if "." in item: + head, path = item.split(".", 1) + obj = self.setdefault(head, nested_param_dict()) + obj[path] = value + else: + super().__setitem__(item, value) + + class DataTablesView(View): model: Model = None - columns: List[tuple] = [] - - COL_SEARCH_REGEX = r"columns\[(?P[0-9]{1,})\]\[search\]\[value\]" - COL_SEARCHABLE_REGEX = r"columns\[(?P[0-9]{1,})\]\[searchable\]" - COL_SEARCHABLE_AS_REGEX_REGEX = r"columns\[(?P[0-9]{1,})\]\[search\]\[regex\]" - COL_ORDERABLE_REGEX = r"columns\[(?P[0-9]{1,})\]\[orderable\]" - - search_regex: re.Pattern = None - searchable_regex: re.Pattern = None - searchable_as_regex_regex: re.Pattern = None - order_regex: re.Pattern = None - - def __init__(self, **kwargs): - super().__init__(**kwargs) - self.search_regex = re.compile(self.COL_SEARCH_REGEX) - self.searchable_regex = re.compile(self.COL_SEARCHABLE_REGEX) - self.searchable_as_regex_regex = re.compile(self.COL_SEARCHABLE_AS_REGEX_REGEX) - self.order_regex = re.compile(self.COL_ORDERABLE_REGEX) + columns: list[tuple] = [] def get_model_qs(self, request: HttpRequest, *args, **kwargs): return self.model.objects - def get_param(self, request: HttpRequest, key: str, cast=str, default=""): - return cast(request.GET.get(key, default)) - - def filter_qs(self, search_string: str, column_conf: dict): + def filter_qs(self, table_conf: dict): # Search filter_q = Q() - for id, c in column_conf.items(): - _c = self.columns[id][0] + for id, c in table_conf["columns"].items(): + _c = self.columns[int(id)][0] if c["searchable"] and len(_c) > 0: - if len(c["search"]) and len(_c): - if c["regex"]: - filter_q |= Q(**{f'{_c}__iregex': c["search"]}) + if len(c["search"]["value"]) and len(_c): + if c["search"]["regex"]: + filter_q |= Q(**{f'{_c}__iregex': c["search"]["value"]}) else: - filter_q |= Q(**{f'{_c}__icontains': c["search"]}) - if len(search_string) > 0: - filter_q |= Q(**{f'{_c}__icontains': search_string}) + filter_q |= Q(**{f'{_c}__icontains': c["search"]["value"]}) + if len(table_conf["search"]["value"]) > 0: + filter_q |= Q(**{f'{_c}__icontains': table_conf["search"]["value"]}) return filter_q - def get_columns_config(self, get: dict): - columns = defaultdict( - lambda: { - "searchable": False, - "orderable": False, - "regex": False, - "search": "" - } - ) - for c in get: - _r = self.search_regex.findall(c) - if _r: - columns[int(_r[0])]["search"] = get[c] - _r_s = self.searchable_regex.findall(c) - if _r_s: - columns[int(_r_s[0])]["searchable"] = get[c] == "true" - _r_s_r = self.searchable_as_regex_regex.findall(c) - if _r_s_r: - columns[int(_r_s_r[0])]["regex"] = get[c] == "true" - _r_o = self.order_regex.findall(c) - if _r_o: - columns[int(_r_o[0])]["orderable"] = get[c] == "true" - return columns + def get_table_config(self, get: dict): + _cols = nested_param_dict() + for c, v in get.items(): + _keys = [_k for _k in c.replace("]", "").split("[")] + _cols[".".join(_keys)] = v + return _cols - def order_str(self, order_col, order_dir, column_conf: dict): - order = "" - _o = column_conf[order_col] - if _o["orderable"]: - if order_dir == 'desc': - order = '-' + self.columns[order_col][0] - else: - order = self.columns[order_col][0] + def get_order(self, table_conf: dict): + order = [] + for oc, od in table_conf["order"].items(): + _c = table_conf["columns"][od["column"]] + if _c["orderable"]: + if od["column"] == 'desc': + order.append('-' + self.columns[int(od["column"])][0]) + else: + order.append(self.columns[int(od["column"])][0]) return order def render_template(self, request: HttpRequest, template: str, ctx: dict): @@ -102,30 +77,26 @@ class DataTablesView(View): ) def get(self, request: HttpRequest, *args, **kwargs): - - # Get all our Params out of GET - length = self.get_param(request, "length", int) - start = self.get_param(request, "start", int) - search_string = self.get_param(request, "search[value]") - order_col = self.get_param(request, "order[0][column]", int, 0) - order_dir = self.get_param(request, "order[0][dir]") - draw = self.get_param(request, "draw", int) - + table_conf = self.get_table_config(request.GET) + draw = int(table_conf["draw"]) + start = int(table_conf["start"]) + length = int(table_conf["length"]) limit = start + length - column_conf = self.get_columns_config(request.GET) - # Searches - filter_q = Q() | self.filter_qs(search_string, column_conf) + filter_q = Q() | self.filter_qs(table_conf) # Build response rows items = [] - qs = self.get_model_qs(request, *args, **kwargs).filter(filter_q).order_by() - - # Apply ordering - order = self.order_str(order_col, order_dir, column_conf) - if order != "": - qs = qs.order_by(order) + qs = self.get_model_qs( + request, + *args, + **kwargs + ).filter( + filter_q + ).order_by( + *self.get_order(table_conf) + ) # build output for row in qs[start:limit]: