diff --git a/horilla_views/cbv_methods.py b/horilla_views/cbv_methods.py index acaaeb0c6..d96d471d1 100644 --- a/horilla_views/cbv_methods.py +++ b/horilla_views/cbv_methods.py @@ -2,6 +2,7 @@ horilla/cbv_methods.py """ +import types import uuid from urllib.parse import urlencode from venv import logger @@ -236,6 +237,14 @@ def sortby( ) reverse = cache[request.session.session_key].reverse none_ids = [] + none_queryset = [] + model = queryset.model + model_attr = getattribute(model, sort_key) + is_method = isinstance(model_attr, types.FunctionType) + if not is_method: + none_queryset = queryset.filter(**{f"{sort_key}__isnull": True}) + none_ids = list(none_queryset.values_list("id", flat=True)) + queryset = queryset.exclude(id__in=none_ids) def _sortby(object): result = getattribute(object, attr=sort_key) @@ -258,10 +267,14 @@ def sortby( except TypeError: none_queryset = list(queryset.filter(id__in=none_ids)) queryset = sorted(queryset.exclude(id__in=none_ids), key=_sortby, reverse=order) - queryset = queryset + none_queryset cache[request.session.session_key].reverse = order - order = "asc" if not order else "desc" + if order: + order = "asc" + queryset = list(queryset) + list(none_queryset) + else: + queryset = list(none_queryset) + list(queryset) + order = "desc" setattr(request, "sort_order", order) setattr(request, "sort_key", sort_key) return queryset diff --git a/horilla_views/generic/cbv/views.py b/horilla_views/generic/cbv/views.py index 6cf64d9f0..614da8b65 100644 --- a/horilla_views/generic/cbv/views.py +++ b/horilla_views/generic/cbv/views.py @@ -52,6 +52,23 @@ class HorillaListView(ListView): bulk_select_option: bool = True action_method: str = """""" + """ + eg: + def accessibility( + request, instance: object = None, user_perms: PermWrapper = [], *args, **kwargs + )->bool: + # True if accessible to the action else False + return True + + actions = [ + { + "action": "Edit", + "accessibility": "path_to_your.accessibility", # path to your accessibility method + "attrs": '''{instance_attributes_called_like_this}''', + }, + etc.. + ] + """ actions: list = [] option_method: str = "" @@ -392,7 +409,23 @@ class HorillaCardView(ListView): search_url: str = "" details: dict = {} + """ + eg: + def accessibility( + request, instance: object = None, user_perms: PermWrapper = [], *args, **kwargs + )->bool: + # True if accessible to the action else False + return True + actions = [ + { + "action": "Edit", + "accessibility": "path_to_your.accessibility", # path to your accessibility method + "attrs": '''{instance_attributes_called_like_this}''', + }, + etc.. + ] + """ actions: list = [] card_attrs: str = """""" diff --git a/horilla_views/templates/generic/group_by.html b/horilla_views/templates/generic/group_by.html index 84ec53d15..ef40937a7 100644 --- a/horilla_views/templates/generic/group_by.html +++ b/horilla_views/templates/generic/group_by.html @@ -199,13 +199,15 @@ {% if not option_method %}
{% for option in options %} - - - + {% if option.accessibility|accessibility:instance %} + + + + {% endif %} {% endfor %}
{% else %} {{instance|getattribute:option_method|safe}} {% endif %} @@ -215,13 +217,15 @@ {% if not action_method %}
{% for action in actions %} - - - + {% if action.accessibility|accessibility:instance %} + + + + {% endif %} {% endfor %}
{% else %} {{instance|getattribute:action_method|safe}} {% endif %} diff --git a/horilla_views/templates/generic/horilla_card.html b/horilla_views/templates/generic/horilla_card.html index 2c232c7c9..65e934009 100644 --- a/horilla_views/templates/generic/horilla_card.html +++ b/horilla_views/templates/generic/horilla_card.html @@ -48,9 +48,11 @@ > diff --git a/horilla_views/templates/generic/horilla_list.html b/horilla_views/templates/generic/horilla_list.html index 8becf9257..c03e6bc90 100644 --- a/horilla_views/templates/generic/horilla_list.html +++ b/horilla_views/templates/generic/horilla_list.html @@ -218,13 +218,15 @@ {% if not option_method %}
{% for option in options %} - - - + {% if option.accessibility|accessibility:instance %} + + + + {% endif %} {% endfor %}
{% else %} {{instance|getattribute:option_method|safe}} {% endif %} @@ -234,13 +236,15 @@ {% if not action_method %}
{% for action in actions %} - - - + {% if action.accessibility|accessibility:instance %} + + + + {% endif %} {% endfor %}
{% else %} {{instance|getattribute:action_method|safe}} {% endif %} diff --git a/horilla_views/templates/generic/reload_select_field.html b/horilla_views/templates/generic/reload_select_field.html index e7170b829..b423c5700 100644 --- a/horilla_views/templates/generic/reload_select_field.html +++ b/horilla_views/templates/generic/reload_select_field.html @@ -10,3 +10,4 @@ $("#{{dynamic_id}} [name={{field.name}}]").change(function (e) { } }); + diff --git a/horilla_views/templatetags/generic_template_filters.py b/horilla_views/templatetags/generic_template_filters.py index 2fd04b8a4..78fbd6342 100644 --- a/horilla_views/templatetags/generic_template_filters.py +++ b/horilla_views/templatetags/generic_template_filters.py @@ -10,8 +10,12 @@ import types from django import template from django.conf import settings +from django.contrib.auth.context_processors import PermWrapper from django.template.defaultfilters import register +from base.thread_local_middleware import _thread_locals +from horilla.config import import_method + register = template.Library() @@ -60,3 +64,16 @@ def format(string: str, instance: object): formatted_string = string.format(**format_context) return formatted_string + + +@register.filter("accessibility") +def accessibility(method: str, instance=None): + if method: + request = getattr(_thread_locals, "request") + method = import_method(method) + return method( + request, + instance, + PermWrapper(request.user), + ) + return True