idlesign/django-sitetree

Не отрабатывает tem.is_current и item.in_current_branch [RUS]

brestows opened this issue · 5 comments

Добрый день, буду писать по-русски, раз автор его знате )

Есть у меня две проблемки с вашим замечательной либой для Django.
Для начала опишу что я сделал.
Я сделал кастомную модель:

class CustomTreeItem(TreeItemBase):
    icon = models.CharField(
        _('Icon Title'), max_length=200,
        help_text=_('Icon class for menu title'), blank=True, default='fa fa-dashboard')

Модель довольно проста, просто добавляет иконку, что бы при генерации меню, выставлялась нужная иконка. После чего я сделал кастомный шаблон для генерации меню:

{% load i18n sitetree %}

	{% for item in sitetree_items %}
		{% if item.has_children %}
			{% if item.in_current_branch %}
				<li class="active treeview">
			{% else %}
				<li class="treeview">
			{% endif %}
		{% else %}
			<li>
		{% endif %}
				<a href="{% sitetree_url for item %}"
				   	{% if item.hint %}
				   		title="{{ item.hint }}"
				   	{% endif %}
				   	{% if item.is_current or item.in_current_branch %}
				   		class="{{ item.is_current|yesno:"current_item ," }}{{ item.in_current_branch|yesno:"current_branch," }}"
					{% endif %}>
					<i class="{{item.icon}}"></i>
					<span>{{item.title_resolved}} - {{item.in_current_branch}}</span>
				</a>
				{% if item.has_children %}
					<ul class="treeview-menu">
						{% sitetree_children of item for menu template "pyDesk/menu.html" %}
					</ul>
				{% endif %}
			</li>
	{% endfor %}

Тут я обнаружил первую проблему, мне надо что бы при нажатии на ссылку, добавлялся соответствующий класс, но вот почему то это не происходит. Не могу понять какова логика проверки is_current так как оно всегда возвращает False.
Меню генерируется автоматически путем команды:

./manage.py sitetree_resync_apps

Код файла sitetree.py в приложении для генерации меню:

from sitetree.utils import tree, item
from django.conf import settings
from django.utils.translation import gettext_lazy as _, gettext
from django.core.management.base import CommandError
import ldap


def get_tree_item_name(ldap_attribute):
    ad = ldap.initialize(getattr(settings, 'AUTH_LDAP_SERVER_URI'))
    basedn = getattr(settings, 'AUTH_LDAP_BASE_DN')
    try:
        ad.protocol_version = ldap.VERSION3
        ad.simple_bind_s(
            getattr(settings, 'AUTH_LDAP_BIND_DN'),
            getattr(settings, 'AUTH_LDAP_BIND_PASSWORD')
        )
    except ldap.INVALID_CREDENTIALS:
        raise CommandError(_('Invalid LDAP credentials! Please check your username/password and try again!'))
    except ldap.LDAPError as e:
        print(e)
    try:
        LDAP_FILTER = getattr(settings, 'PYDESK_LDAP_USER_FILTER', ['(objectCategory=person)', '(objectClass=user)'])
        LDAP_FILTER.append("({}=*)".format(ldap_attribute))
        obj_filter = '({}{})'.format(getattr(settings, 'PYDESK_LDAP_USER_FILTER_OPER', '&'), ''.join(LDAP_FILTER))
        ldap_result = ad.search_s(basedn, ldap.SCOPE_SUBTREE, obj_filter, [ldap_attribute])
        result_set = []
        for ldp in ldap_result:
            element = ldp[1][ldap_attribute][0].decode("utf-8")
            if not element in result_set:
                result_set.append(element)
        ad.unbind_s()
        return sorted(result_set)
    except ldap.LDAPError as e:
        print('LDAP ERROR: {}'.format(e))

def generate_menu():
    ldap_attribute = getattr(settings, 'PYDESK_ADDRESSBOOK_ROOT_ATTRIBUTE', 'l')
    lang_list = getattr(settings, 'LANGUAGE', [('en', _('English')), ])
    tree_menu_list = getattr(settings, 'PYDESK_SITETREE_NAME', ['navigator', ])
    item_tree = get_tree_item_name(ldap_attribute)
    root_tree = []
    for root in tree_menu_list:
        for lang in lang_list:
            root_tree.append('{}_{}'.format(root, lang[0]))

    sitetrees_address_book = []
    for menu in root_tree:
        children = []
        print(_('Generate menu: {}'.format(menu)))
        for element in item_tree:
            print(_('Generate element: {}'.format(element)))
            children.append(
                item(_(element), '/addressbook?{}={}'.format(ldap_attribute, element),
                     access_loggedin=True,
                     url_as_pattern=False,
                     icon='fa fa-building',
                     access_by_perms='addressbook.view_address_book',
                     alias=element
                     )
            )
        sitetrees_address_book.append(
            tree(menu, items=[
                item(gettext('Address Book'), '/addressbook', children=children,
                     access_loggedin=True,
                     url_as_pattern=False,
                     icon='fa fa-address-book',
                     access_by_perms='addressbook.view_address_book',
                     alias='addressbook'
                     )])
        )

    return sitetrees_address_book

sitetrees = generate_menu()

Просьба помочь разобравться с такой как мне кажется очевидной проблемой, просто я ее не могу понять (

Есть еще вопрос, но не уверен что он напрямую касается вашей библиотеки, но с ней связаной, используя все выше сказанное, почему то не могу отредактировать пункты меню, получаю ошибку:

Reverse for 'pyDesk_customtreeitem_changelist' not found. 'pyDesk_customtreeitem_changelist' is not a valid view function or pattern name.
Request Method:	POST
Request URL:	http://localhost:8000/admin/sitetree/tree/25/change/item_818/
Django Version:	3.0
Exception Type:	NoReverseMatch
Exception Value:	
Reverse for 'pyDesk_customtreeitem_changelist' not found. 'pyDesk_customtreeitem_changelist' is not a valid view function or pattern name.
Exception Location:	/home/carie/PyProjects/pyDesk/venv/lib64/python3.7/site-packages/django/urls/resolvers.py in _reverse_with_prefix, line 676
Python Executable:	/home/carie/PyProjects/pyDesk/venv/bin/python
Python Version:	3.7.5
Python Path:	
['/home/carie/PyProjects/pyDesk/src',
 '/home/carie/PyProjects/pyDesk',
 '/usr/lib64/python37.zip',
 '/usr/lib64/python3.7',
 '/usr/lib64/python3.7/lib-dynload',
 '/home/carie/PyProjects/pyDesk/venv/lib64/python3.7/site-packages',
 '/home/carie/PyProjects/pyDesk/venv/lib64/python3.7/site-packages/setuptools-40.8.0-py3.7.egg',
 '/home/carie/PyProjects/pyDesk/venv/lib64/python3.7/site-packages/pip-19.0.3-py3.7.egg',
 '/home/carie/PyProjects/pyDesk/venv/lib/python3.7/site-packages',
 '/home/carie/PyProjects/pyDesk/venv/lib/python3.7/site-packages/setuptools-40.8.0-py3.7.egg',
 '/home/carie/PyProjects/pyDesk/venv/lib/python3.7/site-packages/pip-19.0.3-py3.7.egg']
Server time:	Вс, 22 Дек 2019 22:48:17 +0100

pyDesk - название приложения.
Я только разбираюсь с python и Django так что не судите строго )
Буду раз если поможете, спасибо за Ваши труды.

Здравствуйте,

Не могу понять какова логика проверки is_current так как оно всегда возвращает False.

Логика такая: берём текущий URL и для него пытаемся найти соответствие в дереве, упомянутом в шаблоне. Если обнаружен элемент дерева с подходящим URL, то он помечается текущим is_current.

Просьба помочь разобравться с такой как мне кажется очевидной проблемой, просто я ее не могу понять (

По всей видимости sitetree не может найти однозначного соответствия. Это означает, что нужно сверить, есть текущий URL в дереве. Можете посмотреть на демо. Там нет GET параметров для пунктов меню, но в целом принцип выделения текущего пункта меню должен быть ясен.
Помимо этого, хочу заметить что генерировать кучу элементов дерева (у вас их 800+?) затратно, как с точки зрения памяти, так и быстродействия. Рассмотрите возможность использования шаблонных URL.

Есть еще вопрос, но не уверен что он напрямую касается вашей библиотеки, но с ней связаной, используя все выше сказанное, почему то не могу отредактировать пункты меню, получаю ошибку:

Здесь нужно бы посмотреть пристальнее. Используется последняя версия sitetree?
Из предположений пока только:

  • Проверить, не связано ли это с регистром букв в имени приложения PyDesk.
  • Проверить подключено ли приложение PyDesk.
  • Посмотреть, какие шаблоны URL доступны, возможно это поможет натолкнуть на решение. Обычно список шаблонов выводиться на странице с отладочной информацией (когда DEBUG включен).

Спасибо за Ваш ответ. Касательно шаблонных URL, спасибо за совет, может действительно будет удобнее, хотя элементов всего 40 для каждого языка, но учитывая что оно генерируется автоматически, может быть вариант куда более массивного меню)

Здесь нужно бы посмотреть пристальнее. Используется последняя версия sitetree?
Из предположений пока только:

версия sitetree самая последняя.

Проверить, не связано ли это с регистром букв в имени приложения PyDesk.

Вроде все везде однотипно написано, но пересмотрю внимательно

Проверить подключено ли приложение PyDesk.

приложение pyDesk подключено так как модифицированная модель TreeItem в нем, да и это клюлчевое приложение.

Посмотреть, какие шаблоны URL доступны, возможно это поможет натолкнуть на решение. Обычно список шаблонов выводиться на странице с отладочной информацией (когда DEBUG включен).

Тут не совсем понимаю о чем речь идет.

Буду вечером за компьютером перепроверю все еще раз. Как я понимаю при изменении стандартной модели, ничего другого переопределять не надо ?

Тут не совсем понимаю о чем речь идет.

В settings.py нужно выставить DEBUG = True, после попытки захода на страницу, которую Джанго не может найти, она выведет страницу с описанием ошибки типа https://djangobook.com/wp-content/uploads/figure2_2.png

В этом примере под числами 1, 2, 3 указаны URL известные Джанго.

Как я понимаю при изменении стандартной модели, ничего другого переопределять не надо ?

Всё верно.

У меня доступны вот такие url: https://hkar.ru/10D73 а вот ошибка: https://hkar.ru/10D74.
Ошибку получаю не зависимо от того вручную я создаю пункт меню в админке, или редактирую сгенерированный.

Если поможет то вот лог ошибки в pycharm:

Internal Server Error: /admin/sitetree/tree/32/change/item_add/
Traceback (most recent call last):
  File "/home/carie/PyProjects/pyDesk/venv/lib64/python3.7/site-packages/django/core/handlers/exception.py", line 34, in inner
    response = get_response(request)
  File "/home/carie/PyProjects/pyDesk/venv/lib64/python3.7/site-packages/django/core/handlers/base.py", line 115, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "/home/carie/PyProjects/pyDesk/venv/lib64/python3.7/site-packages/django/core/handlers/base.py", line 113, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/home/carie/PyProjects/pyDesk/venv/lib64/python3.7/site-packages/django/utils/decorators.py", line 130, in _wrapped_view
    response = view_func(request, *args, **kwargs)
  File "/home/carie/PyProjects/pyDesk/venv/lib64/python3.7/site-packages/django/views/decorators/cache.py", line 44, in _wrapped_view_func
    response = view_func(request, *args, **kwargs)
  File "/home/carie/PyProjects/pyDesk/venv/lib64/python3.7/site-packages/django/contrib/admin/sites.py", line 231, in inner
    return view(request, *args, **kwargs)
  File "/home/carie/PyProjects/pyDesk/venv/lib64/python3.7/site-packages/sitetree/admin.py", line 221, in item_add
    return self.add_view(request, extra_context={'tree': tree})
  File "/home/carie/PyProjects/pyDesk/venv/lib64/python3.7/site-packages/django/contrib/admin/options.py", line 1638, in add_view
    return self.changeform_view(request, None, form_url, extra_context)
  File "/home/carie/PyProjects/pyDesk/venv/lib64/python3.7/site-packages/django/utils/decorators.py", line 43, in _wrapper
    return bound_method(*args, **kwargs)
  File "/home/carie/PyProjects/pyDesk/venv/lib64/python3.7/site-packages/django/utils/decorators.py", line 130, in _wrapped_view
    response = view_func(request, *args, **kwargs)
  File "/home/carie/PyProjects/pyDesk/venv/lib64/python3.7/site-packages/django/contrib/admin/options.py", line 1522, in changeform_view
    return self._changeform_view(request, object_id, form_url, extra_context)
  File "/home/carie/PyProjects/pyDesk/venv/lib64/python3.7/site-packages/django/contrib/admin/options.py", line 1570, in _changeform_view
    return self.response_add(request, new_object)
  File "/home/carie/PyProjects/pyDesk/venv/lib64/python3.7/site-packages/sitetree/admin.py", line 161, in response_add
    return self._redirect(request, super(TreeItemAdmin, self).response_add(request, obj, post_url_continue))
  File "/home/carie/PyProjects/pyDesk/venv/lib64/python3.7/site-packages/django/contrib/admin/options.py", line 1167, in response_add
    current_app=self.admin_site.name,
  File "/home/carie/PyProjects/pyDesk/venv/lib64/python3.7/site-packages/django/urls/base.py", line 87, in reverse
    return iri_to_uri(resolver._reverse_with_prefix(view, prefix, *args, **kwargs))
  File "/home/carie/PyProjects/pyDesk/venv/lib64/python3.7/site-packages/django/urls/resolvers.py", line 676, in _reverse_with_prefix
    raise NoReverseMatch(msg)
django.urls.exceptions.NoReverseMatch: Reverse for 'pyDesk_customtreeitem_change' not found. 'pyDesk_customtreeitem_change' is not a valid view function or pattern name.
[23/Dec/2019 18:04:01] "POST /admin/sitetree/tree/32/change/item_add/ HTTP/1.1" 500 140034

я убрал кастомную модель (закоментил
SITETREE_MODEL_TREE_ITEM = 'pyDesk.CustomTreeItem'
а так же убрал регистрацию в админке:


class CustomItemAdmin(TreeItemAdmin):
    fieldsets = (
        (_('Basic settings'), {
            'fields': ('parent', 'title', 'url', 'icon')
        }),
        (_('Access settings'), {
            'classes': ('collapse',),
            'fields': ('access_loggedin', 'access_guest', 'access_restricted', 'access_permissions', 'access_perm_type')
        }),
        (_('Display settings'), {
            'classes': ('collapse',),
            'fields': ('hidden', 'inmenu', 'inbreadcrumbs', 'insitetree')
        }),
        (_('Additional settings'), {
            'classes': ('collapse',),
            'fields': ('hint', 'description', 'alias', 'urlaspattern')
        }),
    )


override_item_admin(CustomItemAdmin)

т.е в штатном режиме все работает, проблема с NoReversMatch получаю когда применяю кастомную модель для элемента меню.

Может я чего еще не доделал для переопределения модели элемента меню ?

Я разобрался с проблемой, касательно редактирования элементов с использованием кастомной модели. Спасибо за Ваше время. Думаю что с определением is_current тоже разберусь.