Skip to content

Instantly share code, notes, and snippets.

@Jragon
Created February 15, 2023 14:02
Show Gist options
  • Save Jragon/d7acabb05238f040fed86c44652c4658 to your computer and use it in GitHub Desktop.
Save Jragon/d7acabb05238f040fed86c44652c4658 to your computer and use it in GitHub Desktop.
import enum
from copy import copy
from types import DynamicClassAttribute
from typing import List
from django.db.models import QuerySet
class OrderableMeta(enum.EnumMeta):
def __new__(metacls, classname, bases, classdict, **kwds):
fields = []
members = copy(classdict._member_names)
for key in members:
value = classdict[key]
if (
isinstance(value, (list, tuple))
and len(value) > 1
and isinstance(value[-1], str)
):
*value, field = value
value = tuple(value)
else:
field = value
fields.append(field)
fields.append(f"-{field}")
dict.__setitem__(classdict, key, value[0])
classdict[f"{key}_desc"] = f"-{value[0]}"
cls = super().__new__(metacls, classname, bases, classdict, **kwds)
for member, field in zip(cls.__members__.values(), fields):
member._field_ = field
return enum.unique(cls)
@property
def names(cls):
empty = ["__empty__"] if hasattr(cls, "__empty__") else []
return empty + [member.name for member in cls]
@property
def items(cls):
empty = [(None, cls.__empty__)] if hasattr(cls, "__empty__") else []
return empty + [(member.value, member.field) for member in cls]
@property
def fields(cls):
return [field for _, field in cls.items]
@property
def values(cls):
return [value for value, _ in cls.items]
class OrderableEnum(enum.Enum, metaclass=OrderableMeta):
def __repr__(self):
return f"{self.__class__.__qualname__}.{self._name_}"
def __str__(self):
return str(self.value)
@DynamicClassAttribute
def field(self):
return self._field_
class OrderableFieldsEnum(str, OrderableEnum):
pass
def order_queryset(
queryset: QuerySet,
ordering: OrderableFieldsEnum | List[OrderableFieldsEnum] | None,
default: str | List[str] | None = None,
):
if ordering is not None:
if isinstance(ordering, list):
orders = [o.field for o in ordering]
else:
orders = [ordering.field]
else:
orders = []
if default is not None:
if isinstance(default, list):
orders.extend(default)
else:
orders.append(default)
return queryset.order_by(*orders)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment