如何在Django模板中实现面包屑?

在谷歌search“Django面包屑”时提供的一些解决scheme包括使用模板和block.super,基本上只是扩展基本块并添加当前页面。 http://www.martin-geber.com/thought/2007/10/25/breadcrumbs-django-templates/

http://www.djangosnippets.org/snippets/1289/ – 提供了一个模板标签,但我不确定这将工作,如果你没有正确申报你的urls.py。

我想知道什么是最好的方法? 如果你之前已经实施了面包屑,你是怎么做到的?

—编辑 –

我的问题是:在Django中有没有普遍接受的做面包屑的方法,但是从我看到的答案是没有的,并且有许多不同的解决scheme,我不确定谁来给予正确的答案,因为我使用了一个使用block.super方法的变体,下面的所有答案都可以工作。

我想这太过于主观的问题了。

注意:以下提供了完整的代码片断,因为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模板中(让我们看一下咨询页面),你只需要input:

 //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。 第一个允许创build简单的URL,文字部分和URL部分。 或者只是取消链接的文本(例如作为面包屑path中的最后一个项目)。 第二,实际上可以带参数命名的url! 另外它需要一个标题作为第一个参数。

这是一个应该放到/ templatetags目录中的模板标签文件。

只需在create_crumb方法中更改图像的path,就可以了!

不要忘记在你的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, ie: {% 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="/mediahttp://img.dovov.comarrow.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 

Django的pipe理视图模块具有自动breadcumbs,这是这样实现的:

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

所以这里有一些内置的支持

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

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

面包屑并不是一个简单的线性列表,他们已经在哪里了 – 这就是浏览器的历史。 一个简单的清单,他们已经不是一个很好的面包屑痕迹,因为它不反映任何意义。

对于我们的大部分视图函数,导航是相当固定的,并且基于模板/视图/ URLdevise。 在我们的案例中,有很多细节的钻研,面包屑反映了缩小 – 我们有一个“领域”,“列表”,“父母”和“孩子”。 它们从一般到具体形成一个简单的层次结构。

在大多数情况下,一个明确定义的URL可以细分成面包屑的一个很好的痕迹。 事实上,这是一个良好的URLdevise的testing – 该URL可以被解释为面包屑并显示给用户有意义的。

例如,对于一些查看function,我们提供的信息是“多对多”join的一部分,有两个候选父母。 URL可以说一件事,但会话的上下文堆栈说另一个。

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

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

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

我有同样的问题,最后我做了简单的django tempalate标签: https : //github.com/prymitive/bootstrap-breadcrumbs

http://www.djangosnippets.org/snippets/1289/ – 提供了一个模板标签,但我不确定这将工作,如果你没有正确申报你的urls.py。

如果你没有正确声明你的urls.py什么都不会起作用。 话虽如此,它看起来不像从urls.pyimport。 事实上,它看起来像正确使用该标签,你仍然需要传递模板一些variables。 好吧,这不是真的:间接通过breadcrumb标签调用的默认url标签。 但据我所知,甚至没有实际称之为标签; 所有出现的url都是本地创build的variables。

但我不擅长parsing模板标签定义。 所以说在代码中的其他地方,它神奇地复制了url标签的function。 这个用法似乎是你将parameter passing给反向查找。 同样,无论您的项目是什么,您都应该configurationurls.py ,以便通过反向查找来访问任何视图。 面包屑尤其如此。 想一想:

 home > accounts > my account 

应该帐户, 永远持有一个任意的,硬编码的url? “我的帐户”可以持有一个任意的,硬编码的url吗? 某种方式,不知何故,你会写一个面包屑,使你的urls.py被颠倒过来。 这实际上只会发生在两个地方之一:在您看来,通过调用reverse ,或在模板中,调用模板标签,模仿reverse的function。 可能有一些理由偏好前者而不是后者(链接片段locking你),但避免urls.py文件的逻辑configuration不是其中之一。

试试django-mptt 。

用于在您的Django Model类中实现Modified Preorder Tree Traversal(MPTT)并使用Model实例的树的实用工具。

像这样的东西可能适合你的情况:

在视图中捕获整个url,并从中build立链接。 这将需要修改你的urls.py,每个需要面包屑的视图和你的模板。

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

原来的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的“目录”部分显示为链接文本。 一个解决这个问题的办法就是在定义breadcrumb函数的文件中保留一个字典(可能不是很好)

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

你可能想尝试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. 

还有一些实用function(例如,你可以在例子中看到的name_from_pk )为你的面包屑自动生成漂亮的名字,而不需要大量的代码。

我为此创build了模板filter。

将你的自定义filter(我已经命名为makebreadcrumbs),像这样的request.path:

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

我们需要将URL名称空间作为arg传递给我们的filter。

也使用安全筛选器,因为我们的筛选器将返回需要parsing为html内容的string。

自定义filter应如下所示:

 @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. 

重要:

我们filter中'value'的分裂部分应该和urls.py中的名字空间相等,所以可以调用reverse方法。

希望它有帮助。

显然,没有人能最好的回答,但是出于实际的原因,我觉得这是值得考虑的天真的方式。 只是覆盖和重写整个面包屑… (至less在官方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

真实世界用例:

  • Django奥斯卡: 基地模板 , 简单的面包
  • Djangopipe理员: 基本模板 , 简单的面包 , 权限检查面包屑