template - ¿Cómo implementar migas de pan en una plantilla de Django?
sistema de plantillas django (11)
http://www.djangosnippets.org/snippets/1289/ - proporciona una etiqueta de plantilla pero no estoy seguro de que esto funcione si no tiene su urls.py correctamente declarado.
Nada funcionará si no tienes tu urls.py
correctamente declarado. Habiendo dicho eso, no parece importar desde urls.py
De hecho, parece que usar correctamente esa etiqueta, aún debe pasar algunas variables a la plantilla. De acuerdo, eso no es del todo cierto: indirectamente a través de la etiqueta url
predeterminada, que llama la etiqueta de breadcrumb
navegación. Pero, por lo que puedo entender, ni siquiera llama a esa etiqueta; todas las ocurrencias de url
son variables creadas localmente.
Pero no soy experto en analizar definiciones de etiquetas de plantilla. Así que diga en otro lugar en el código que mágicamente replica la funcionalidad de la etiqueta url. El uso parece ser que pasas argumentos a una búsqueda inversa. De nuevo, no importa cuál sea tu proyecto, tu urls.py
debe configurarse para que se pueda llegar a cualquier vista con una búsqueda inversa. Esto es especialmente cierto con las migas de pan. Piénsalo:
home > accounts > my account
¿Deben las cuentas, alguna vez tener una url arbitraria y codificada? ¿Podría "mi cuenta" tener una url arbitraria y codificada? De alguna manera, de alguna manera vas a escribir migas de pan de tal manera que tu urls.py
se invierta. Eso realmente solo sucederá en uno de dos lugares: en su opinión, con una llamada para reverse
, o en la plantilla, con una llamada a una etiqueta de plantilla que imita la funcionalidad de reverse
. Puede haber razones para preferir el primero sobre el segundo (en el cual el fragmento vinculado lo bloquea), pero evitar una configuración lógica de su archivo urls.py
no es uno de ellos.
Algunas de las soluciones proporcionadas al hacer una búsqueda en Google de "migas de pan Django" incluyen el uso de plantillas y block.super, básicamente ampliando los bloques base y añadiéndole la página actual. http://www.martin-geber.com/thought/2007/10/25/breadcrumbs-django-templates/
http://www.djangosnippets.org/snippets/1289/ - proporciona una etiqueta de plantilla, pero no estoy seguro de que esto funcione si no tiene su urls.py correctamente declarado.
Me pregunto ¿cuál es la mejor manera? Y si ha implementado migas de pan antes, ¿cómo lo hizo?
--- Editar -
Mi pregunta estaba destinada a ser: ¿existe un método general aceptado para hacer migas de pan en Django, pero a partir de las respuestas que veo que no hay, y hay muchas soluciones diferentes, no estoy seguro de a quién otorgar la respuesta correcta, ya que Usé una variación de usar el método block.super, mientras que todas las respuestas a continuación funcionarían.
Supongo que esta es una pregunta demasiado subjetiva.
Algo como esto puede funcionar para su situación:
Capture toda la URL en su vista y cree enlaces desde ella. Esto requerirá modificar tu urls.py, cada vista que debe tener migas de pan, y tus plantillas.
Primero capturaría la URL completa en su archivo urls.py
urls.py original...
(r''^myapp/$'', ''myView''),
(r''^myapp/(?P<pk>.+)/$'', ''myOtherView''),
...
nuevo urls.py
...
(r''^(?P<whole_url>myapp/)$'', ''myView''),
(r''^(?P<whole_url>myapp/(?P<pk>.+)/)$'', ''myOtherView''),
...
Entonces, en su opinión, algo como:
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)
...
Que se debe extraer en una función que se importa en las vistas que lo necesitan
Luego, en su plantilla imprima las migas de pan
myTemplate.html...
<div class="breadcrumb-nav">
<ul>
{% for breadcrumb in breadcrumbs %}
<li><a href="{{ breadcrumb.url }}">{{ breadcrumb.slug }}</a></li>
{% endfor %}
</ul>
</div>
...
Una de las deficiencias de hacerlo de esta manera es que, tal como está, solo se puede mostrar la parte del ''directorio'' de la url como el texto del enlace. Una solución para esto fuera de mi cabeza (probablemente no sea una buena) sería mantener un diccionario en el archivo que define la función de ruta de navegación.
De todos modos esa es una manera en la que puedes lograr migas de pan, ¡salud! :)
Creé un filtro de plantilla para esto.
Aplica tu filtro personalizado (lo he llamado ''makebreadcrumbs'') al request.path de esta manera:
{% with request.resolver_match.namespace as name_space %}
{{ request.path|makebreadcrumbs:name_space|safe }}
{% endwith %}
Necesitamos pasar el espacio de nombres de url como un arg a nuestro filtro.
También use un filtro seguro, ya que nuestro filtro devolverá cadenas que deben resolverse como contenido html.
El filtro personalizado debería verse así:
@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.
Importante:
las partes divididas del ''valor'' en nuestro filtro deben ser iguales al espacio de nombres en urls.py, de modo que se puede invocar el método inverso.
Espero que haya ayudado.
El módulo de vista administrativa Django tiene breadcumbs automáticos, que se implementan de la siguiente manera:
{% block breadcrumbs %}
<div class="breadcrumbs">
<a href="{% url ''admin:index'' %}">{% trans ''Home'' %}</a>
{% block crumbs %}
{% if title %} › {{ title }}{% endif %}
{% endblock %}
</div>
{% endblock %}
Entonces hay algún tipo de soporte incorporado para esto ...
Es posible que desee probar django-headcrumbs (no se preocupe, no van a comer sus cerebros).
Es muy liviano y absolutamente sencillo de usar, todo lo que tienes que hacer es anotar tus puntos de vista (porque la definición de la estructura de migas en las plantillas me parece una locura) con un decorador que explica cómo volver desde la vista dada.
Aquí hay un ejemplo de la documentación:
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.
También hay algunas funciones de utilidad (p name_from_pk
Ej., name_from_pk
que se puede ver en el ejemplo) que generan automágicamente buenos nombres para sus migas sin tener que escribir gran cantidad de código.
Las funciones de mi vista emiten las migas de pan como una lista simple.
Parte de la información se guarda en la sesión del usuario. Indirectamente, sin embargo, proviene de las URL.
Las rutas de exploración no son una simple lista lineal de dónde han estado; para eso está el historial del navegador. Una simple lista de dónde han estado no es una buena ruta de navegación porque no refleja ningún significado.
Para la mayoría de nuestras funciones de visualización, la navegación es bastante fija y se basa en el diseño de plantilla / vista / URL. En nuestros casos, hay una gran cantidad de detalles, y las migas de pan reflejan ese estrechamiento: tenemos un "reino", una "lista", un "padre" y un "niño". Forman una jerarquía simple de general a específico.
En la mayoría de los casos, una URL bien definida se puede dividir trivialmente en un buen rastro de migas de pan. De hecho, esa es una prueba para un buen diseño de URL: la URL puede interpretarse como migas de pan y mostrarse de manera significativa a los usuarios.
Para algunas funciones de vista, donde presentamos información que es parte de una unión "muchos a muchos", por ejemplo, hay dos padres candidatos. La URL puede decir una cosa, pero la pila de contexto de la sesión dice otra.
Por esa razón, nuestras funciones de vista deben dejar pistas de contexto en la sesión para que podamos emitir rutas de navegación.
Obviamente, nadie responde mejor, pero por una razón práctica, creo que vale la pena considerarlo de manera ingenua. Simplemente sobrescriba y reescriba toda la django.contrib.breadcrumb
... (al menos hasta que se django.contrib.breadcrumb
el django.contrib.breadcrumb
oficial)
Sin ser demasiado elegante, es mejor mantener las cosas simples. Ayuda al recién llegado a entender. Es extremadamente personalizable (por ejemplo, comprobación de permisos , icono de ruta de navegación , caracteres separadores , ruta de navegación activa , etc.)
Plantilla base
<!-- 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>
Plantilla de implementación
Más adelante en cada página reescribimos y sobrescribimos todo el bloque de ruta de navegación.
<!-- 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
Casos de uso de Realworld:
- Django Oscar: plantilla base , pan simple
- Django Admin: plantilla base , pan simple , comprobación de permiso breadcrumb
Pruebe django-mptt .
Utilidades para implementar Modified Preorder Tree Traversal (MPTT) con sus clases de modelos de Django y trabajar con árboles de instancias de modelos.
Pruebe django-breadcrumbs : un middleware conectable que agrega una ruta de navegación invocable / iterable en su objeto de solicitud.
Admite vistas simples, vistas genéricas y la aplicación Django FlatPages.
Tuve el mismo problema y finalmente hice una etiqueta simple de django tempalate para ello: https://github.com/prymitive/bootstrap-breadcrumbs
Nota: proporciono el fragmento completo a continuación, ya que djangosnippets ha sido meticuloso últimamente.
Genial, alguien encontró http://www.djangosnippets.org/snippets/1289/ fragmento :-) El uso de mi etiqueta de plantilla es bastante simple.
Para responder a su pregunta, no existe un mecanismo django "incorporado" para hacer frente a las migas de pan, pero sí nos proporciona la siguiente mejor opción: etiquetas de plantilla personalizadas.
Imagina que quieres tener migas de pan así:
Services -> Programming
Services -> Consulting
Entonces probablemente tendrá algunas urls con nombre: "servicios", y "programación", "consultoría":
(r''^services/$'',
''core.views.services'',
{},
''services''),
(r''^services/programming$'',
''core.views.programming'',
{},
''programming''),
(r''^services/consulting$'',
''core.views.consulting'',
{},
''consulting''),
Ahora dentro de su plantilla html (solo mire la página de consulta) todo lo que tiene que poner es:
//consulting.html
{% load breadcrumbs %}
{% block breadcrumbs %}
{% breadcrumb_url ''Services'' services %}
{% breadcrumb_url ''Consulting'' consulting %}
{% endblock %}
Si desea utilizar algún tipo de texto personalizado dentro de la ruta de navegación, y no desea vincularlo, puede usar la etiqueta de ruta de navegación.
//consulting.html
{% load breadcrumbs %}
{% block breadcrumbs %}
{% breadcrumb_url ''Services'' services %}
{% breadcrumb_url ''Consulting'' consulting %}
{% breadcrumb ''We are great!'' %}
{% endblock %}
Hay situaciones más complicadas en las que es posible que desee incluir una identificación de un objeto en particular, que también es fácil de hacer. Este es un ejemplo que es más realista:
{% 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 %}
Fragmento de las migas de pan de DaGood
Proporciona dos etiquetas de plantilla para usar en sus plantillas HTML: breadcrumb y breadcrumb_url. El primero permite crear url simple, con la porción de texto y la porción de url. O solo texto sin enlace (como el último elemento en el rastro de migas de pan, por ejemplo). El segundo, ¡realmente puede tomar la url nombrada con argumentos! Además, toma un título como primer argumento.
Este es un archivo de plantilla que debe ir a su directorio / templatetags.
Simplemente cambie la ruta de la imagen en el método create_crumb y estará listo para comenzar.
¡No te olvides de {% load breadcrumbs%} en la parte superior de tu plantilla 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