在谷歌搜索“Django面包屑”时提供的一些解决方案包括使用模板和block.super,基本上只是扩展基本块并将当前页面添加到其中。 http://www.martin-geber.com/thought/2007/10/25/breadcrumbs-django-templates/
http://www.djangosnippets.org/snippets/1289/ - 提供了一个模板标记,但如果您没有正确声明urls.py,我不确定这是否会有用。
我想知道最好的方法是什么?如果您之前已经实现了面包屑,那么它是如何做到的?
---编辑 -
我的问题是:在Django中是否有一种普遍接受的做面包屑的方法,但从我看到的答案中没有,并且有许多不同的解决方案,我不确定是谁给出了正确的答案to,因为我使用了block.super方法的变体,而以下所有答案都可以使用。
我猜这是一个太主观的问题。
答案 0 :(得分:43)
注意:我提供了下面的完整代码段,因为djangosnippets最近很挑剔。
很酷,有人确实发现了my代码段:-)使用我的模板标签非常简单。
要回答你的问题,没有用于处理面包屑的“内置”django机制,但它确实为我们提供了下一个最好的东西:自定义模板标签。
想象一下,你想要像这样的面包屑:
Services -> Programming
Services -> 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 %}
如果您想在面包屑中使用某种自定义文字,并且不想将其链接,则可以使用 breadcrumb 标记。
//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 %}
提供两个模板标记以在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 %s" % (crumb, title)
return crumb
答案 1 :(得分:12)
Django管理视图模块具有自动面包屑,其实现如下:
{% block breadcrumbs %}
<div class="breadcrumbs">
<a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
{% block crumbs %}
{% if title %} › {{ title }}{% endif %}
{% endblock %}
</div>
{% endblock %}
所以对此有一些内置的支持..
答案 2 :(得分:6)
我的视图函数将面包屑作为简单列表发出。
某些信息保存在用户的会话中。然而,间接地,它来自URL。
Breadcrumbs并不是一个简单的线性列表,它们就是这样的 - 这就是浏览器历史记录的用途。他们去过的地方的简单列表并没有成为良好的面包屑痕迹,因为它没有反映出任何意义。
对于我们的大多数视图功能,导航非常固定,并且基于模板/视图/ URL设计。在我们的案例中,有很多深入细节,面包屑反映了缩小 - 我们有一个“领域”,一个“列表”,一个“父母”和一个“孩子”。它们形成了从一般到特定的简单层次结构。
在大多数情况下,一个明确定义的URL可以简单地分解成一个很好的痕迹痕迹。实际上,这是一个良好的URL设计测试 - URL可以被解释为面包屑并有意义地显示给用户。
对于一些视图函数,我们提供的信息是“多对多”联接的一部分,例如,有两个候选父项。 URL可以说一件事,但会话的上下文堆栈说另一个。
因此,我们的视图函数必须在会话中留下上下文线索,以便我们可以发出面包屑。
答案 3 :(得分:5)
尝试django-breadcrumbs - 一个可插入的中间件,在您的请求对象中添加可调用/可迭代的面包屑。
它支持简单视图,通用视图和Django FlatPages应用程序。
答案 4 :(得分:5)
我遇到了同样的问题,最后我为它制作了简单的django模板标签:https://github.com/prymitive/bootstrap-breadcrumbs
答案 5 :(得分: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
文件的逻辑配置不是其中之一。
答案 6 :(得分:3)
尝试django-mptt。
使用Django Model类实现Modified Preorder Tree Traversal(MPTT)并使用Model实例树的实用程序。
答案 7 :(得分:1)
显然,没有一个最好的答案,但出于实际原因,我发现值得考虑天真的方式。 只是覆盖并重写整个面包屑...... (至少在官方django.contrib.breadcrumb
发布之前)
不要过于花哨,最好保持简单。它有助于新人理解。它是非常可定制的(例如权限检查, 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 %}
Realworld用例:
答案 8 :(得分:0)
捕获视图中的整个网址并从中创建链接。这需要修改urls.py,每个需要包含面包屑的视图和模板。
首先,您将在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>
...
这样做的一个缺点是,就目前而言,您只能将网址的“目录”部分显示为链接文本。我的头顶(可能不是一个好的)的一个解决方法是在文件中保留一个定义面包屑功能的字典。
无论如何,一种方式你可以完成面包屑,欢呼:)
答案 9 :(得分: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
),可以自动为您的面包屑生成漂亮的名称,而无需编写大量代码。
答案 10 :(得分:0)
我为此创建了模板过滤器。
将自定义过滤器(我将其命名为'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.
重要的:
我们过滤器中'value'的拆分部分应该等于urls.py中的命名空间,因此可以调用reverse方法。
希望它有所帮助。
答案 11 :(得分:0)
您还可以通过在视图中添加面包屑属性来减少使用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 %}
答案 12 :(得分: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>
只有不会引发 404
的链接是可点击的。