Как реализовать панировочные сухари в шаблоне Django?
В некоторых решениях, связанных с поиском Google для "Django breadcrumbs", можно использовать шаблоны и block.super, в основном просто расширяя базовые блоки и добавляя к ним текущую страницу. http://www.martin-geber.com/thought/2007/10/25/breadcrumbs-django-templates/
http://www.djangosnippets.org/snippets/1289/ - содержит тег шаблона, но я не уверен, что это сработает, если у вас нет правильного urls.py объявлено.
Мне интересно, что лучший способ? И если вы внедрили панировочные сухари перед тем, как вы это сделали?
--- Изменить -
Мой вопрос должен был быть: есть ли общепринятый способ делать панировочные сундуки в Django, но из ответов, которые я вижу, нет, и есть много разных решений, я не уверен, кто должен дать правильный ответ к, поскольку я использовал вариацию использования метода block.super, в то время как все приведенные ниже ответы будут работать.
Полагаю, это слишком субъективный вопрос.
Ответы
Ответ 1
Примечание. Ниже приведен полный фрагмент кода, поскольку в последнее время 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 %}
Если вы хотите использовать какой-то специальный текст внутри хлебной крошки и не хотите связывать его, вы можете использовать вместо него тег хлебной крошки.
//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 %s" % (crumb, title)
return crumb
Ответ 2
В модуле просмотра admin в Django есть автоматические подшивки, которые реализованы следующим образом:
{% block breadcrumbs %}
<div class="breadcrumbs">
<a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
{% block crumbs %}
{% if title %} › {{ title }}{% endif %}
{% endblock %}
</div>
{% endblock %}
Итак, для этого есть какая-то встроенная поддержка.
Ответ 3
Мои функции представления испускают панировочные сухари как простой список.
Некоторая информация хранится в сеансе пользователя. Косвенно, однако, он исходит из URL-адреса.
Breadcrumbs - это не простой линейный список того, где они были, - для чего предназначена история браузера. Простой список того, где они были, не создает хороший след в виде хлебной крошки, потому что он не отражает никакого смысла.
Для большинства наших функций просмотра навигация довольно фиксированная и основана на шаблоне/представлении/URL-дизайне. В наших случаях есть много бурения в деталях, и сухарь отражает это сужение - у нас есть "царство", "список", "родитель" и "ребенок". Они образуют простую иерархию от общего к конкретному.
В большинстве случаев четко определенный URL-адрес может быть тривиально разбит на приятный след панировочных сухарей. Действительно, этот тест для хорошего дизайна URL-адресов - URL-адрес можно интерпретировать как панировочные сундуки и значимо отображаться для пользователей.
Для нескольких функций просмотра, где мы представляем информацию о том, что часть соединения "многие ко многим" объединяет, например, двух родителей-кандидатов. URL-адрес может сказать одно, но стек контекста сеанса говорит другое.
По этой причине наши функции просмотра должны оставлять контекстные подсказки в сеансе, чтобы мы могли испускать панировочные сундуки.
Ответ 4
Попробуйте django-breadcrumbs - подключаемое промежуточное программное обеспечение, которое добавляет патчи, вызываемые/повторяемые в вашем объекте запроса.
Он поддерживает простые представления, общие представления и приложение Django FlatPages.
Ответ 5
У меня была такая же проблема, и, наконец, я сделал простой тег django tempalate для него: https://github.com/prymitive/bootstrap-breadcrumbs
Ответ 6
http://www.djangosnippets.org/snippets/1289/ - содержит тег шаблона, но я не уверен, что это сработает, если у вас нет urls.py правильно объявлено.
Ничего не будет работать, если у вас нет надлежащего объявления urls.py
. Сказав это, он выглядит не так, как будто он импортирует из urls.py
. На самом деле, похоже, что правильно использовать этот тег, вам все равно придется передать шаблон некоторым переменным. Ладно, это не совсем так: косвенно через тег url
по умолчанию, который вызывает тег breadcrumb
. Но, насколько я могу судить, он даже не называет этот тег; все вхождения url
являются локально созданными переменными.
Но я не эксперт по разбору определений тегов шаблонов. Так скажите где-то еще в коде, он волшебным образом повторяет функциональность тега url. Использование, похоже, заключается в том, что вы передаете аргументы в обратный поиск. Опять же, независимо от вашего проекта, вы urls.py
должны быть настроены таким образом, чтобы любое представление можно было получить с помощью обратного поиска. Это особенно верно в отношении сухарей. Подумайте об этом:
home > accounts > my account
Должны ли учетные записи, когда-либо иметь произвольный, hardcoded url? Могла ли "моя учетная запись" когда-либо иметь произвольный, жесткий код? В некотором роде, как-то вы собираетесь писать панировочные сухари таким образом, чтобы ваш urls.py
был отменен. Это действительно произойдет только в одном из двух мест: по вашему мнению, с вызовом reverse
или в шаблоне с вызовом тега шаблона, который имитирует функциональность reverse
. Могут быть причины предпочесть первое по сравнению с последним (в который привязанный фрагмент блокирует вас), но избежать логической конфигурации вашего файла urls.py
не является одним из них.
Ответ 7
Попробуйте django-mptt.
Утилиты для реализации измененного обхода дерева заказов (MPTT) с вашими классами Django Model и работа с деревьями экземпляров Model.
Ответ 8
Очевидно, что нет лучшего ответа, но по практическим соображениям я считаю, что стоит рассмотреть наивный способ. Просто перезапишите и перепишите всю сводку... (по крайней мере, до официального выпуска 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
Случаи использования Realworld:
Ответ 9
Что-то вроде этого может работать для вашей ситуации:
Захватите весь URL-адрес в своем представлении и сделайте ссылки на него. Это потребует изменения вашего urls.py, каждого представления, которое должно иметь панировочные сухари и ваши шаблоны.
Сначала вы захватили бы весь URL-адрес в файле urls.py
Оригинал urls.py
...
(r'^myapp/$', 'myView'),
(r'^myapp/(?P<pk>.+)/$', 'myOtherView'),
...
новый urls.py
...
(r'^(?P<whole_url>myapp/)$', 'myView'),
(r'^(?P<whole_url>myapp/(?P<pk>.+)/)$', 'myOtherView'),
...
Тогда в вашем представлении что-то вроде:
views.py
...
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)
...
Который следует вытащить в функцию, которая импортируется в представления, которые в ней нуждаются
Затем в вашем шаблоне распечатайте панировочные сухари
myTemplate.html
...
<div class="breadcrumb-nav">
<ul>
{% for breadcrumb in breadcrumbs %}
<li><a href="{{ breadcrumb.url }}">{{ breadcrumb.slug }}</a></li>
{% endfor %}
</ul>
</div>
...
Один из недостатков этого способа заключается в том, что, поскольку он стоит, вы можете отображать только часть "каталога" URL-адреса в качестве текста ссылки. Одно исправление этого с моей головы (возможно, не очень хорошее) - это сохранить словарь в файле, который определяет функцию палитры.
В любом случае, один способ, которым вы могли бы сделать панировочные сухари, приветствия:)
Ответ 10
Возможно, вы захотите попробовать 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
, которые вы можете увидеть в примере), которые автоматически генерируют приятные имена для ваших крошек, не вызывая большого количества кода.
Ответ 11
Я создал шаблонный фильтр для этого.
Примените свой настраиваемый фильтр (я назвал его "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 ' > '.join(my_crumbs)
# return whole list of crumbs joined by the right arrow special character.
Важно:
разделенные части "значения" в нашем фильтре должны быть равны пространству имен в urls.py, поэтому можно вызвать обратный метод.
Надеюсь, что это помогло.
Ответ 12
Вы также можете уменьшить размер плиты, необходимой для управления панировочными сухарями, используя 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 %}