diff --git a/docs/configuration.md b/docs/configuration.md index a224ea83..3566975a 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -289,9 +289,9 @@ Add a template for your model on your main template directory, e.g [app/templates/admin/app_name/model_name/submit_line.html](https://github.com/farridav/django-jazzmin/tree/master/tests/test_app/library/books/templates/admin/loans/bookloan/submit_line.html) ```djangotemplate -{# extends "admin/submit_line.html" #} +{#% extends "admin/submit_line.html" %#} -{% block extra-actions %} +{#% block extra-actions %#} {# For a simple link #}
@@ -302,7 +302,7 @@ e.g [app/templates/admin/app_name/model_name/submit_line.html](https://github.co
-{% endblock %} +{#% endblock %#} ``` If you are adding a button that needs processing with the form, e.g (Save and send) you will need to add the diff --git a/jazzmin/settings.py b/jazzmin/settings.py index b53d64ed..3b5084f7 100644 --- a/jazzmin/settings.py +++ b/jazzmin/settings.py @@ -30,6 +30,8 @@ ############ # Links to put along the nav bar "topmenu_links": [], + # Whether or not we use icons on the top menu + "topmenu_icons": False, ############# # User Menu # ############# diff --git a/jazzmin/templatetags/jazzmin.py b/jazzmin/templatetags/jazzmin.py index c3fd872b..069581ed 100644 --- a/jazzmin/templatetags/jazzmin.py +++ b/jazzmin/templatetags/jazzmin.py @@ -31,7 +31,7 @@ get_admin_url, make_menu, has_fieldsets_check, - regroup_available_apps, + regroup_apps, ) User = get_user_model() @@ -64,7 +64,7 @@ def get_side_menu(context: Context, using: str = "available_apps") -> List[Dict] # If we are using custom grouping, overwrite available_apps based on our grouping if options.get("custom_menu") and options["custom_menu"]: - available_apps = regroup_available_apps(available_apps, options["custom_menu"]) + available_apps = regroup_apps(available_apps, options["custom_menu"]) for app in available_apps: app_label = app["app_label"].lower() @@ -88,13 +88,18 @@ def get_side_menu(context: Context, using: str = "available_apps") -> List[Dict] custom_link_names = [x.get("name", "").lower() for x in app_custom_links] model_ordering = list( - filter(lambda x: x.lower().startswith("{}.".format(app_label)) or x.lower() in custom_link_names, ordering,) + filter( + lambda x: x.lower().startswith("{}.".format(app_label)) or x.lower() in custom_link_names, + ordering, + ) ) if len(menu_items): if model_ordering: menu_items = order_with_respect_to( - menu_items, model_ordering, getter=lambda x: x.get("model_str", x.get("name", "").lower()), + menu_items, + model_ordering, + getter=lambda x: x.get("model_str", x.get("name", "").lower()), ) app["models"] = menu_items menu.append(app) @@ -420,7 +425,8 @@ def deleted(x: str) -> Dict: elif "changed" in sub_message: sub_message["changed"]["fields"] = get_text_list( - [gettext(field_name) for field_name in sub_message["changed"]["fields"]], gettext("and"), + [gettext(field_name) for field_name in sub_message["changed"]["fields"]], + gettext("and"), ) if "name" in sub_message["changed"]: sub_message["changed"]["name"] = gettext(sub_message["changed"]["name"]) @@ -443,7 +449,7 @@ def style_bold_first_word(message: str) -> SafeText: message_words = escape(message).split() if not len(message_words): - return "" + return mark_safe("") message_words[0] = "{}".format(message_words[0]) diff --git a/jazzmin/utils.py b/jazzmin/utils.py index 8eab3407..63159d84 100644 --- a/jazzmin/utils.py +++ b/jazzmin/utils.py @@ -1,12 +1,12 @@ import logging -from typing import List, Union, Dict, Set, Callable +from typing import List, Union, Dict, Set, Callable, Any from urllib.parse import urlencode from django.apps import apps from django.contrib.admin import ListFilter from django.contrib.admin.helpers import AdminForm from django.contrib.auth.models import AbstractUser -from django.db.models.base import ModelBase +from django.db.models.base import ModelBase, Model from django.db.models.options import Options from django.utils.translation import gettext @@ -33,16 +33,13 @@ def order_with_respect_to(original: List, reference: List, getter: Callable = la return [y for x, y in sorted(zip(ranking, original), key=lambda x: x[0])] -def get_admin_url( - instance: Union[str, ModelBase], admin_site: str = "admin", from_app: bool = False, **kwargs: str -) -> str: +def get_admin_url(instance: Any, admin_site: str = "admin", from_app: bool = False, **kwargs: str) -> str: """ Return the admin URL for the given instance, model class or . string """ url = "#" try: - if type(instance) == str: app_label, model_name = instance.split(".") model_name = model_name.lower() @@ -150,16 +147,7 @@ def get_view_permissions(user: AbstractUser) -> Set[str]: lower_perms = [] for perm in perms: app, perm_codename = perm.split(".") -<<<<<<< HEAD lower_perms.append("{app}.{perm_codename}".format(app=app, perm_codename=perm_codename.lower())) -======= - lower_perms.append( - "{app}.{perm_codename}".format( - app=app, - perm_codename=perm_codename.lower(), - ) - ) ->>>>>>> 3ec6d11 (test) return {x.replace("view_", "") for x in lower_perms if "view" in x or "change" in x} @@ -176,12 +164,7 @@ def make_menu( menu = [] for link in links: - - perm_matches = [] - for perm in link.get("permissions", []): - perm_matches.append(user.has_perm(perm)) - - if not all(perm_matches): + if not all([user.has_perm(perm) for perm in link.get("permissions", [])]): continue # Url links @@ -217,16 +200,7 @@ def make_menu( # App links elif "app" in link and allow_appmenus: children = [ -<<<<<<< HEAD {"name": child.get("verbose_name", child["name"]), "url": child["url"], "children": None} -======= - { - "name": child.get("verbose_name", child["name"]), - "url": child["url"], - "children": None, - "icon": options["icons"].get(child["model"].lower()), - } ->>>>>>> 3ec6d11 (test) for child in get_app_admin_urls(link["app"], admin_site=admin_site) if child["model"] in model_permissions ] @@ -252,7 +226,7 @@ def has_fieldsets_check(adminform: AdminForm) -> bool: return True -def regroup_available_apps(available_apps: List[Dict], grouping: Dict[str, List[str]]) -> List[Dict]: +def regroup_apps(available_apps: List[Dict], grouping: Dict[str, List[str]]) -> List[Dict]: # Make a list of all apps, and all models, keyed on app name or model name all_models, all_apps = {}, {} for app in available_apps: diff --git a/tests/test_app/library/settings.py b/tests/test_app/library/settings.py index d046500f..a6a98cef 100644 --- a/tests/test_app/library/settings.py +++ b/tests/test_app/library/settings.py @@ -71,15 +71,25 @@ DATABASES = { "default": dj_database_url.config( - env="DATABASE_URL", conn_max_age=500, default="sqlite:///{}".format(os.path.join(BASE_DIR, "db.sqlite3")), + env="DATABASE_URL", + conn_max_age=500, + default="sqlite:///{}".format(os.path.join(BASE_DIR, "db.sqlite3")), ) } AUTH_PASSWORD_VALIDATORS = [ - {"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",}, - {"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",}, - {"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",}, - {"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",}, + { + "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator", + }, + { + "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", + }, + { + "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator", + }, + { + "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator", + }, ] LANGUAGE_CODE = "en" @@ -146,6 +156,7 @@ {"app": "books"}, {"app": "loans"}, ], + # Whether or not we use icons on the top menu "topmenu_icons": True, ############# # User Menu # @@ -179,7 +190,7 @@ } ] }, - # Dont generate a menu based off installed apps, instead, craft one using this app/arbitrary name -> model mapping + # Dont generate a side menu from installed apps, instead, craft one using this app/arbitrary name -> model mapping "custom_menu": {}, # Custom icons for side menu apps/models See https://fontawesome.com/icons?d=gallery&m=free # for a list of icon classes