Created
February 15, 2023 14:02
-
-
Save Jragon/d7acabb05238f040fed86c44652c4658 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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