47

在 Google 搜索“Django 面包屑”时提供的一些解决方案包括使用模板和 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 方法的变体,而以下所有答案都可以。

我想这是一个过于主观的问题。

4

14 回答 14

46

注意:我在下面提供了完整的片段,因为 djangosnippets 最近很挑剔。

很酷,实际上有人找到了我的代码片段 :-) 我的模板标签的使用相当简单。

要回答您的问题,没有用于处理面包屑的“内置”django 机制,但它确实为我们提供了下一个最好的东西:自定义模板标签。

想象一下,你想要这样的面包屑:

Services -> Programming
Services -> Consulting

然后你可能会有几个命名的 url:“services”、“programming”、“consulting”:

    (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 %}

在更多涉及的情况下,您可能希望包含特定对象的 id,这也很容易做到。这是一个更现实的例子:

{% 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 方法中更改图像的路径即可!

不要忘记在您的 html 模板顶部添加 {% load breadcrumbs %}!

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
于 2009-05-06T18:56:55.297 回答
15

Django 管理视图模块具有自动面包屑,其实现方式如下

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

因此,对此有某种内置支持..

于 2012-01-16T11:14:58.770 回答
7

我的视图函数将面包屑作为一个简单的列表发出。

一些信息保存在用户的会话中。然而,它间接地来自 URL。

面包屑不是它们去过的地方的简单线性列表——这就是浏览器历史记录的用途。他们去过的地方的简单列表并不能成为一个好的面包屑路径,因为它没有反映任何意义。

对于我们的大多数视图功能,导航是相当固定的,并且基于模板/视图/URL 设计。在我们的案例中,有很多深入细节,面包屑反映了这种缩小——我们有一个“领域”、一个“列表”、一个“父级”和一个“子级”。它们形成了一个从一般到具体的简单层次结构。

在大多数情况下,一个定义明确的 URL 可以很容易地分解成一个很好的面包屑痕迹。实际上,这是对良好 URL 设计的一项测试—— URL 可以被解释为面包屑并有意义地显示给用户。

对于一些视图函数,我们提供的信息是“多对多”连接的一部分,例如,有两个候选父节点。URL 可能说一件事,但会话的上下文堆栈说另一件事。

出于这个原因,我们的视图函数必须在会话中留下上下文线索,以便我们可以发出面包屑。

于 2009-05-05T21:16:25.800 回答
5

我遇到了同样的问题,最后我为它制作了简单的 django 模板标签:https ://github.com/prymitive/bootstrap-breadcrumbs

于 2012-10-04T13:15:49.047 回答
5

试试django-breadcrumbs——一个可插入的中间件,它在你的请求对象中添加一个可调用/可迭代的面包屑。

它支持简单视图、通用视图和 Django FlatPages 应用程序。

于 2010-02-25T16:31:21.227 回答
3

http://www.djangosnippets.org/snippets/1289/ - 提供了一个模板标签,但如果你没有正确声明你的 urls.py,我不确定这会起作用。

如果您没有urls.py正确申报,任何事情都不会奏效。话虽如此,它看起来不像是从urls.py. 事实上,看起来要正确使用该标签,您仍然需要向模板传递一些变量。好吧,这并不完全正确:间接通过标签调用的默认url标签。breadcrumb但据我所知,它甚至没有真正调用那个标签。所有出现的url都是本地创建的变量。

但我不是解析模板标签定义的专家。所以说在代码的其他地方它神奇地复制了 url 标签的功能。用法似乎是您将参数传递给反向查找。同样,无论您的项目是什么,您urls.py都应该进行配置,以便可以通过反向查找访问任何视图。对于面包屑尤其如此。想一想:

home > accounts > my account

帐户是否应该拥有任意的硬编码网址? “我的帐户”可以拥有任意的硬编码网址吗?以某种方式,您将以某种方式编写面包屑,从而使您的结果urls.py被反转。这实际上只会发生在以下两个地方之一:在您看来,调用reverse. 或在模板中调用模仿reverse. 可能有理由更喜欢前者而不是后者(链接片段将您锁定在其中),但避免urls.py文件的逻辑配置不是其中之一。

于 2009-05-05T21:46:09.097 回答
3

尝试django-mptt

用于使用 Django 模型类实现修改的预排序树遍历 (MPTT) 并使用模型实例树的实用程序。

于 2009-07-18T09:12:49.013 回答
2

显然,没有一个最佳答案,但出于实际原因,我发现值得考虑幼稚的方式。只需覆盖并重写整个面包屑......(至少在正式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 %}

实用性

现实世界的用例:

于 2016-09-21T08:02:56.140 回答
1

您还可以通过向视图添加 crumbs 属性来减少使用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 %}
于 2018-12-12T16:10:50.533 回答
0

这样的事情可能适用于您的情况:

在您的视图中捕获整个 URL 并从中创建链接。这将需要修改您的 urls.py、需要有面包屑的每个视图以及您的模板。

首先,您将在 urls.py 文件中捕获整个 URL

原始网址.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'),
...

然后在你看来是这样的:

视图.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)
...

应该将其拉出到导入到需要它的视图中的函数中

然后在您的模板中打印出面包屑

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

这样做的一个缺点是,就目前而言,您只能将 url 的“目录”部分显示为链接文本。我想到的一个解决方法(可能不是一个好的方法)是在定义面包屑功能的文件中保留一个字典。

无论如何,这是你可以完成面包屑的一种方式,干杯:)

于 2009-05-05T23:00:58.777 回答
0

你可能想试试django-headcrumbs(别担心,它们不会吃掉你的大脑)。

它非常轻量级并且使用起来绝对简单,您所要做的就是用一个解释如何从给定视图返回的装饰器来注释您的视图(因为在模板中定义 crumbs 结构对我来说听起来很疯狂)。

这是文档中的一个示例:

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,您可以在示例中看到)可以自动为您的面包屑生成漂亮的名称,而无需您编写大量代码。

于 2013-03-06T09:44:17.300 回答
0

收集当前 url 的所有可调用路径的通用方法可以通过以下代码片段解决:

from django.urls import resolve, Resolver404

path_items = request.path.split("/")
path_items.pop(0)
path_tmp = ""

breadcrumb_config = OrderedDict()
for path_item in path_items:
    path_tmp += "/" + path_item
    try:
        resolve(path_tmp)
        breadcrumb_config[path_item] = {'is_representative': True, 'current_path': path_tmp}
    except Resolver404:
        breadcrumb_config[path_item] = {'is_representative': False, 'current_path': path_tmp}

如果resolve函数无法从任何 urlpattern 中获取真实路径,Resolver404则会抛出异常。对于这些项目,我们将is_representative标志设置为 false。OrderedDict breadcrumb_config之后保留具有该配置的面包屑项目。

例如,对于 bootstrap 4 面包屑,您可以在模板中执行以下操作:

<nav aria-label="breadcrumb">
  <ol class="breadcrumb">
      {% for crumb, values in BREADCRUMB_CONFIG.items %}
        <li class="breadcrumb-item {% if forloop.last or not values.is_representative %}active{% endif %}" {% if forloop.last %}aria-current="page"{% endif %}>
            {% if values.is_representative %}
                <a href="{{values.current_path}}">
                    {{crumb}}
                </a>
            {% else %}
                {{crumb}}
            {% endif %}
        </li>
      {% endfor %}
  </ol>
</nav>

只有不会引发 a 的链接404是可点击的。

于 2021-02-02T12:51:16.597 回答
0

我为此创建了模板过滤器。

将您的自定义过滤器(我将其命名为“makebreadcrumbs”)应用到 request.path,如下所示:

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

我们需要将 url 命名空间作为参数传递给我们的过滤器。

还要使用安全过滤器,因为我们的过滤器将返回需要解析为 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 中的命名空间,因此可以调用 reverse 方法。

希望它有所帮助。

于 2016-01-11T16:58:25.120 回答
0

我相信没有比这更简单的了(django 3.2):

 def list(request):
        return render(request, 'list.html', {
            'crumbs' : [
                ("Today", "https://www.python.org/"),
                ("Is", "https://www.python.org/"),
                ("Sunday", "https://www.djangoproject.com/"),
            ]
        })

面包屑.html

<div class="page-title-right">
   <ol class="breadcrumb m-0">
      {% if crumbs %}
            {% for c in crumbs %}
                <li class="breadcrumb-item {{c.2}}"><a href="{{c.1}}">{{c.0}}</a></li>
            {% endfor %}
      {% endif %}
   </ol>
</div>

CSS:

.m-0 {
    margin: 0!important;
}
.breadcrumb {
    display: flex;
    flex-wrap: wrap;
    padding: 0 0;
    margin-bottom: 1rem;
    list-style: none;
    border-radius: .25rem;
}
dl, ol, ul {
    margin-top: 0;
    margin-bottom: 1rem;
}
ol, ul {
    padding-left: 2rem;
}

在此处输入图像描述

于 2021-08-15T09:58:14.277 回答