it-swarm.com.ru

Как реализовать панировочные сухари в шаблоне Django?

Некоторые решения, предоставляемые для поиска в Google «хлебных крошек Джанго», включают использование шаблонов и block.super, в основном просто расширение базовых блоков и добавление к ним текущей страницы. http://www.martin-geber.com/thought/2007/10/25/breadcrumbs-Django-templates/

http://www.djangosnippets.org/snippets/1289/ - предоставляет тег шаблона, но я не уверен, что это сработает, если ваш URL-адрес не был правильно объявлен.

Мне интересно, как лучше? И если вы реализовали панировочные сухари до того, как вы это сделали?

--- Правка --

Мой вопрос должен был быть таким: есть ли общепринятый метод приготовления панировочных сухарей в Django, но из ответов, которые я вижу, нет, и есть много разных решений, я не уверен, кому дать правильный ответ, так как Я использовал вариант использования метода block.super, пока все приведенные ниже ответы будут работать.

Я думаю, тогда это слишком субъективный вопрос.

38
Rasiel

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

Круто, кто-то действительно нашел мой сниппет :-) Использование моего тега шаблона довольно просто.

Чтобы ответить на ваш вопрос, не существует «встроенного» механизма Django для работы с хлебными крошками, но он предоставляет нам следующую лучшую вещь: пользовательские теги шаблонов.

Представьте, что вы хотите иметь такие сухарики:

Services -> Programming
Services -> Consulting

Тогда у вас, вероятно, будет несколько именованных URL-адресов: «услуги» и «программирование», «консалтинг»:

    (r'^services/$',
     'core.views.services',
     {},
     'services'),

    (r'^services/programming$',
     'core.views.programming',
     {},
     'programming'),

    (r'^services/consulting$',
     'core.views.consulting',
     {},
     'consulting'),

Теперь внутри вашего html-шаблона (давайте просто посмотрим на консультационную страницу) все, что вам нужно, это:

//consulting.html
{% load breadcrumbs %}

{% block breadcrumbs %}
{% breadcrumb_url 'Services' services %}
{% breadcrumb_url 'Consulting' consulting %}

{% endblock %}

Если вы хотите использовать какой-то специальный текст внутри хлебной крошки и не хотите связывать его, вы можете вместо этого использовать тег breadcrumb.

//consulting.html
{% load breadcrumbs %}

{% block breadcrumbs %}
  {% breadcrumb_url 'Services' services %}
  {% breadcrumb_url 'Consulting' consulting %}
  {% breadcrumb 'We are great!' %}  
{% endblock %}

Есть более сложные ситуации, когда вы можете захотеть включить идентификатор конкретного объекта, что также легко сделать. Это более реалистичный пример:

{% load breadcrumbs %}

{% block breadcrumbs %}
{% breadcrumb_url 'Employees' employee_list %}
{% if employee.id %}
    {% breadcrumb_url employee.company.name company_detail employee.company.id %}
    {% breadcrumb_url employee.full_name employee_detail employee.id %}
    {% breadcrumb 'Edit Employee ' %}
{% else %}
    {% breadcrumb 'New Employee' %}
{% endif %}

{% endblock %}

Фрагмент DaGood панировочных сухарей

Предоставляет два тега шаблона для использования в ваших шаблонах HTML: breadcrumb и breadcrumb_url. Первый позволяет создать простой URL-адрес с текстовой и URL-частью. Или только несвязанный текст (например, последний элемент в журнале). Во-вторых, может фактически взять названный URL с аргументами! Кроме того, он принимает заголовок в качестве первого аргумента.

Это файл тега шаблона, который должен находиться в каталоге/templatetags.

Просто измените путь к изображению в методе create_crumb и все готово!

Не забудьте {% load breadcrumbs%} в верхней части вашего HTML-шаблона!

from Django import template
from Django.template import loader, Node, Variable
from Django.utils.encoding import smart_str, smart_unicode
from Django.template.defaulttags import url
from Django.template import VariableDoesNotExist

register = template.Library()

@register.tag
def breadcrumb(parser, token):
    """
    Renders the breadcrumb.
    Examples:
        {% breadcrumb "Title of breadcrumb" url_var %}
        {% breadcrumb context_var  url_var %}
        {% breadcrumb "Just the title" %}
        {% breadcrumb just_context_var %}

    Parameters:
    -First parameter is the title of the crumb,
    -Second (optional) parameter is the url variable to link to, produced by url tag, i.e.:
        {% url person_detail object.id as person_url %}
        then:
        {% breadcrumb person.name person_url %}

    @author Andriy Drozdyuk
    """
    return BreadcrumbNode(token.split_contents()[1:])


@register.tag
def breadcrumb_url(parser, token):
    """
    Same as breadcrumb
    but instead of url context variable takes in all the
    arguments URL tag takes.
        {% breadcrumb "Title of breadcrumb" person_detail person.id %}
        {% breadcrumb person.name person_detail person.id %}
    """

    bits = token.split_contents()
    if len(bits)==2:
        return breadcrumb(parser, token)

    # Extract our extra title parameter
    title = bits.pop(1)
    token.contents = ' '.join(bits)

    url_node = url(parser, token)

    return UrlBreadcrumbNode(title, url_node)


class BreadcrumbNode(Node):
    def __init__(self, vars):
        """
        First var is title, second var is url context variable
        """
        self.vars = map(Variable,vars)

    def render(self, context):
        title = self.vars[0].var

        if title.find("'")==-1 and title.find('"')==-1:
            try:
                val = self.vars[0]
                title = val.resolve(context)
            except:
                title = ''

        else:
            title=title.strip("'").strip('"')
            title=smart_unicode(title)

        url = None

        if len(self.vars)>1:
            val = self.vars[1]
            try:
                url = val.resolve(context)
            except VariableDoesNotExist:
                print 'URL does not exist', val
                url = None

        return create_crumb(title, url)


class UrlBreadcrumbNode(Node):
    def __init__(self, title, url_node):
        self.title = Variable(title)
        self.url_node = url_node

    def render(self, context):
        title = self.title.var

        if title.find("'")==-1 and title.find('"')==-1:
            try:
                val = self.title
                title = val.resolve(context)
            except:
                title = ''
        else:
            title=title.strip("'").strip('"')
            title=smart_unicode(title)

        url = self.url_node.render(context)
        return create_crumb(title, url)


def create_crumb(title, url=None):
    """
    Helper function
    """
    crumb = """<span class="breadcrumbs-arrow">""" \
            """<img src="/media/images/arrow.gif" alt="Arrow">""" \
            """</span>"""
    if url:
        crumb = "%s<a href='%s'>%s</a>" % (crumb, url, title)
    else:
        crumb = "%s&nbsp;&nbsp;%s" % (crumb, title)

    return crumb
43
drozzy

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

{% block breadcrumbs %}
    <div class="breadcrumbs">
        <a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
        {% block crumbs %}
            {% if title %} &rsaquo; {{ title }}{% endif %}
        {% endblock %}
    </div>
{% endblock %}

Так что есть какая-то встроенная поддержка для этого ..

12
Otto Kekäläinen

Мои функции просмотра испускают хлебные крошки как простой список.

Некоторая информация хранится в сеансе пользователя. Косвенно, однако, это происходит от URL.

Хлебные крошки - это не простой линейный список того, где они были - для этого и нужна история браузера. Простой список того, где они были, не является хорошим следом крошки, потому что он не отражает никакого смысла.

Для большинства наших функций просмотра навигация довольно фиксирована и основана на дизайне шаблона/представления/URL. В наших случаях много подробностей, и хлебные крошки отражают это сужение - у нас есть «область», «список», «родитель» и «ребенок». Они образуют простую иерархию от общего к конкретному.

В большинстве случаев, четко определенный URL-адрес может быть легко разбит на «хороший след» хлебных крошек. Действительно, это один из тестов на хороший дизайн URL - URL можно интерпретировать как хлебные крошки и многозначительно отображать для пользователей.

Например, для нескольких функций просмотра, где мы представляем информацию, являющуюся частью объединения «многие ко многим», есть два кандидата в родители. URL может сказать одно, а стек контекста сеанса говорит другое. 

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

6
S.Lott

У меня была та же проблема, и, наконец, я сделал для этого простой шаблонный тег Django: https://github.com/prymitive/bootstrap-breadcrumbs

5
Łukasz Mierzwa

Попробуйте Django-breadcrumbs - сменное промежуточное ПО, которое добавляет крошки, вызываемые/повторяемые в вашем объекте запроса.

Он поддерживает простые представления, общие представления и приложение Django FlatPages.

5
minder

http://www.djangosnippets.org/snippets/1289/ - предоставляет тег шаблона, но я не уверен, что это сработает, если у вас не будет должным образом объявлен ваш urls.py.

Ничто не сработает, если у вас нет urls.py должным образом объявленного. Сказав это, он не выглядит так, как будто он импортирует из urls.py. На самом деле, похоже, что для правильного использования этого тега вы все равно должны передать шаблону некоторые переменные. Ладно, это не совсем так: косвенно через тег url по умолчанию, который вызывает тег breadcrumb. Но, насколько я понимаю, он даже не вызывает этот тег; все вхождения url являются локально созданными переменными. 

Но я не эксперт в разборе определений тегов шаблонов. Так, скажем, где-то еще в коде это волшебным образом повторяет функциональность тега url. Похоже, вы используете аргументы для обратного поиска. Опять же, независимо от того, какой у вас проект, вы должны настроить urls.py так, чтобы к любому представлению можно было обратиться с помощью обратного просмотра. Это особенно верно с панировочными сухарями. Думаю об этом:

home > accounts > my account

Должны ли учетные записи, ever содержать произвольный, жестко запрограммированный URL? Может ли «моя учетная запись» когда-либо содержать произвольную, жестко запрограммированную ссылку? Каким-то образом, так или иначе, вы будете писать панировочные сухари так, чтобы ваш urls.py был полностью изменен. Это действительно произойдет только в одном из двух мест: по вашему мнению, с вызовом reverse или в шаблоне, с вызовом тега шаблона, который имитирует функциональность reverse. Могут быть причины, по которым предпочтение отдается первому, а не второму (в котором связанный фрагмент блокирует вас), но избегание логической конфигурации вашего файла urls.py не является одним из них.

3
David Berger

Попробуйте Django-MPTT .

Утилиты для реализации Модифицированного обхода дерева предзаказов (MPTT) с вашими классами Django Model и работы с деревьями экземпляров Model.

3
Tomas Andrle

Очевидно, нет лучшего ответа, но по практическим соображениям я считаю, что стоит рассмотреть наивный путь. Просто переписать и переписать весь хлебный крошки ... (по крайней мере, пока официальный Django.contrib.breadcrumb выпущен)

Не слишком прихотлив, лучше не усложнять. Это помогает новичку понять. Он чрезвычайно настраиваемый (например, проверка прав доступа, значок хлебной крошки, символы-разделители, активная хлебная крошка и т.д. ...)

Базовый шаблон

<!-- File: base.html -->
<html>
<body>
  {% block breadcrumb %}
  <ul class="breadcrumb">
    <li><a href="{% url 'dashboard:index' %}">Dashboard</a></li>
  </ul>
  {% endblock breadcrumb %}
  {% block content %}{% endblock content %}
</body>
</html>

Шаблон реализации

Позже на каждой странице мы переписываем и перезаписываем весь блок хлебных крошек.

<!-- File: page.html -->
{% extends 'base.html' %}
{% block breadcrumb %}
<ul class="breadcrumb">
  <li><a href="{% url 'dashboard:index' %}">Dashboard</a></li>
  <li><a href="{% url 'dashboard:level-1:index' %}">Level 1</a></li>
  <li class="active">Level 2</li>
</ul>
{% endblock breadcrumb %}

Practicallity

Примеры использования в реальном мире:

1
Yeo

Возможно, вы захотите попробовать Django-headcrumbs (не волнуйтесь, они не съедят ваш мозг).

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

Вот пример из документации:

from headcrumbs.decorators import crumb
from headcrumbs.util import name_from_pk

@crumb('Staff')  # This is the root crumb -- it doesn’t have a parent
def index(request):
    # In our example you’ll fetch the list of divisions (from a database)
    # and output it.

@crumb(name_from_pk(Division), parent=index)
def division(request, slug):
    # Here you find all employees from the given division
    # and list them.

Есть также некоторые служебные функции (например, name_from_pk, которые вы можете видеть в примере), которые автоматически генерируют имена Nice для ваших крошек, без необходимости писать много кода.

0
kirelagin

Вы также можете уменьшить плиту котла, необходимую для управления панировочными сухарями, используя Django-view-breadcrumbs , добавив в представление свойство крошек.

urls.py

urlpatterns = [
    ...
    path('posts/<slug:slug>', views.PostDetail.as_view(), name='post_detail'),
    ...
] 

views.py

from Django.views.generic import DetailView
from view_breadcrumbs import DetailBreadcrumbMixin


class PostDetail(DetailBreadcrumbMixin, DetailView):
    model = Post
    template_name = 'app/post/detail.html'

base.html

{% load Django_bootstrap_breadcrumbs %}

{% block breadcrumbs %}
    {% render_breadcrumbs %}
{% endblock %}
0
jackotonye

Я создал шаблонный фильтр для этого.

Примените свой пользовательский фильтр (я назвал его «makebreadcrumbs») к request.path следующим образом:

{% with request.resolver_match.namespace as name_space %}
    {{ request.path|makebreadcrumbs:name_space|safe }}
{% endwith %}

Нам нужно передать пространство имен url как arg нашему фильтру.

Также используйте безопасный фильтр, потому что наш фильтр будет возвращать строку, которая должна быть разрешена как HTML-контент.

Пользовательский фильтр должен выглядеть так:

@register.filter
def makebreadcrumbs(value, arg):
    my_crumbs = []
    crumbs = value.split('/')[1:-1]  # slice domain and last empty value
    for index, c in enumerate(crumbs):
        if c == arg and len(crumbs) != 1:  
        # check it is a index of the app. example: /users/user/change_password - /users/ is the index.
            link = '<a href="{}">{}</a>'.format(reverse(c+':index'), c)
        else:
            if index == len(crumbs)-1:
                link = '<span>{}</span>'.format(c)  
                # the current bread crumb should not be a link.
            else:
                link = '<a href="{}">{}</a>'.format(reverse(arg+':' + c), c)
        my_crumbs.append(link)
    return ' &gt; '.join(my_crumbs)  
    # return whole list of crumbs joined by the right arrow special character.

Важный:

разделенные части 'значения' в нашем фильтре должны быть равны пространству имен в urls.py, поэтому можно вызвать обратный метод.

Надеюсь, это помогло.

0
Sevalad

Нечто подобное может работать для вашей ситуации:

Захватите весь URL в вашем представлении и сделайте ссылки с него. Это потребует изменения вашего urls.py, каждого представления, в котором должны быть хлебные крошки, и ваших шаблонов.

Сначала вы должны захватить весь URL в вашем файле urls.py

...
(r'^myapp/$', 'myView'),
(r'^myapp/(?P<pk>.+)/$', 'myOtherView'),
...
...
(r'^(?P<whole_url>myapp/)$', 'myView'),
(r'^(?P<whole_url>myapp/(?P<pk>.+)/)$', 'myOtherView'),
...

Тогда, на ваш взгляд, что-то вроде:

...
def myView(request, whole_url):
    # dissect the url
    slugs = whole_url.split('/')
    # for each 'directory' in the url create a piece of bread
    breadcrumbs = []
    url = '/'
    for slug in slugs:
        if slug != '':
            url = '%s%s/' % (url, slug)
            breadcrumb = { 'slug':slug, 'url':url }
            breadcrumbs.append(breadcrumb)

    objects = {
        'breadcrumbs': breadcrumbs,
    }
    return render_to_response('myTemplate.html', objects)
...

Который должен быть извлечен в функцию, которая импортируется в представления, которые нуждаются в этом

Затем в вашем шаблоне распечатайте панировочные сухари

...
<div class="breadcrumb-nav">
    <ul>
    {% for breadcrumb in breadcrumbs %}
        <li><a href="{{ breadcrumb.url }}">{{ breadcrumb.slug }}</a></li>
    {% endfor %}
    </ul>
</div>
...

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

В любом случае, это один способ, которым вы могли бы достичь хлебных крошек, ура :)

0
rennat