filter design and wip implementation
Django CI/CD / test (push) Successful in 1m39s Details
Django CI/CD / build-and-push (push) Has been skipped Details

This commit is contained in:
Lukáš Kucharczyk 2024-11-10 15:46:44 +01:00
parent d9290373b0
commit 6f92c740c7
Signed by: lukas
SSH Key Fingerprint: SHA256:vMuSwvwAvcT6htVAioMP7rzzwMQNi3roESyhv+nAxeg
2 changed files with 157 additions and 0 deletions

96
filter-design.md Normal file
View File

@ -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")
```

61
games/filters.py Normal file
View File

@ -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