filter design and wip implementation
This commit is contained in:
parent
d9290373b0
commit
6f92c740c7
|
@ -0,0 +1,96 @@
|
|||
# Django
|
||||
|
||||
Session.objects.filter(timestamp_start__year=2024)
|
||||
|
||||
# JSON
|
||||
```json
|
||||
{
|
||||
"type": "session_start",
|
||||
"operator": "equals",
|
||||
"value": "2024"
|
||||
}
|
||||
```
|
||||
|
||||
# HTML
|
||||
```html
|
||||
<select name="filters">
|
||||
<option value='[{"type": "session_start", "operator": "equals", "value": "2024"}]'>2024</option>
|
||||
<option value='[{"type": "session_start", "operator": "equals", "value": "2023"}]'>2023</option>
|
||||
</select>
|
||||
```
|
||||
|
||||
# Python: Python -> HTML
|
||||
```python
|
||||
filters = [
|
||||
{
|
||||
"type": "session_start",
|
||||
"operator": "equals",
|
||||
"value": "2024"
|
||||
}
|
||||
]
|
||||
|
||||
# predefined values
|
||||
session_start_select = Select(name="filters", children=session_start_options)
|
||||
session_start_options = [
|
||||
Option(value=create_filter("session_start", "equals", value=year))
|
||||
for year in range(2000, 2024)
|
||||
]
|
||||
|
||||
# user-selected values
|
||||
|
||||
|
||||
```
|
||||
|
||||
# Python: JSON -> Django
|
||||
```python
|
||||
filter_types = {
|
||||
"session_start": {
|
||||
"equals": "timestamp_start__exact=",
|
||||
"isnull": "timestamp_start__exact=None",
|
||||
"greater_than": "timestamp_start__gt=",
|
||||
"less_than": "timestamp_start__lt=",
|
||||
},
|
||||
}
|
||||
# filter_string = request.GET.get("filters")
|
||||
filter_string = """
|
||||
{
|
||||
"type": "session_start",
|
||||
"operator": "equals",
|
||||
"value": "2024"
|
||||
}
|
||||
"""
|
||||
def string_to_django_filter_dict(s: str):
|
||||
if s[-1] == "=":
|
||||
s + value
|
||||
key, value = s.split("=")
|
||||
return {key: value}
|
||||
|
||||
filter_obj = json.loads(filter_string)[0]
|
||||
field, operator, value = filter_obj
|
||||
|
||||
if type in filter_types:
|
||||
if operator in filter_types[type]:
|
||||
queryset.filter(Q(**string_to_django_filter_dict(filter_types[type][operator])}))
|
||||
else:
|
||||
return False
|
||||
```
|
||||
|
||||
# Python: Django -> JSON -> URI param
|
||||
```python
|
||||
filters = [
|
||||
{
|
||||
"type": "session_start",
|
||||
"operator": "equals",
|
||||
"value": "2024"
|
||||
}
|
||||
]
|
||||
context = {
|
||||
"filters": json.dumps(filters)
|
||||
}
|
||||
return render("filter.html", context)
|
||||
```
|
||||
|
||||
# Python: Django -> JSON (function)
|
||||
```python
|
||||
create_filter("session_start", "operator": "equals", "value": "2024")
|
||||
```
|
|
@ -0,0 +1,61 @@
|
|||
import json
|
||||
from typing import TypeAlias, TypedDict, TypeVar
|
||||
|
||||
from django.db.models import Model, Q
|
||||
from django.db.models.query import QuerySet
|
||||
|
||||
filter_types = {
|
||||
"session_start": {
|
||||
"equals": "timestamp_start__year__exact=",
|
||||
"isnull": "timestamp_start__exact=None",
|
||||
"greater_than": "timestamp_start__gt=",
|
||||
"less_than": "timestamp_start__lt=",
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
class Filter(TypedDict):
|
||||
name: str
|
||||
operator: str
|
||||
value: str
|
||||
|
||||
|
||||
FilterList: TypeAlias = list[Filter]
|
||||
|
||||
|
||||
def string_to_django_filter_dict(s: str, value: str = "") -> dict[str, str | int]:
|
||||
if s[-1] == "=":
|
||||
s += value
|
||||
key, value = s.split("=")
|
||||
return {key: value}
|
||||
|
||||
|
||||
T = TypeVar("T", bound=Model)
|
||||
|
||||
|
||||
def apply_json_filter[T](s: str, queryset: QuerySet[T]) -> QuerySet[T]:
|
||||
filter_obj = urlsafe_json_decode(s)
|
||||
name, operator, value = (filter_obj[k] for k in ["name", "operator", "value"])
|
||||
if name in filter_types:
|
||||
if operator in filter_types[name]:
|
||||
filtered = queryset.filter(
|
||||
Q(**string_to_django_filter_dict(filter_types[name][operator], value))
|
||||
)
|
||||
return filtered
|
||||
return queryset
|
||||
|
||||
|
||||
urlsafe_encode_table = str.maketrans({",": "^", ":": "-", " ": ""})
|
||||
urlsafe_decode_table = str.maketrans({"^": ",", "-": ":"})
|
||||
|
||||
|
||||
def urlsafe_json_encode[T](obj: T) -> str:
|
||||
json_string = json.dumps(obj)
|
||||
safe_string = json_string.translate(urlsafe_encode_table)
|
||||
return safe_string
|
||||
|
||||
|
||||
def urlsafe_json_decode[T](s: str) -> T:
|
||||
unsafe_string = s.translate(urlsafe_decode_table)
|
||||
obj = json.loads(unsafe_string)
|
||||
return obj
|
Loading…
Reference in New Issue