From c96e65eff208c5b772a3d376def1557ea3147358 Mon Sep 17 00:00:00 2001 From: lgomez Date: Mon, 5 Aug 2013 09:33:11 -0300 Subject: [PATCH] Added template tag. some examples. Updated gitignore --- .gitignore | 2 + breadcrumbs/breadcrumbs.py | 9 +- .../breadcrumbs/partial/breadcrumb.html | 12 ++ breadcrumbs/templatetags/__init__.py | 5 + breadcrumbs/templatetags/breadcrumb_tags.py | 110 ++++++++++++++++++ breadcrumbs/utils.py | 45 +++++++ breadcrumbs_sample/settings.py | 4 +- breadcrumbs_sample/templatetag/__init__.py | 0 breadcrumbs_sample/templatetag/models.py | 3 + .../templatetag/templates/dynamic.html | 11 ++ .../templatetag/templates/index.html | 26 +++++ .../templatetag/templates/unpacking.html | 10 ++ breadcrumbs_sample/templatetag/tests.py | 16 +++ breadcrumbs_sample/templatetag/views.py | 29 +++++ breadcrumbs_sample/test.db | Bin 46080 -> 46080 bytes breadcrumbs_sample/urls.py | 17 ++- 16 files changed, 290 insertions(+), 9 deletions(-) create mode 100644 breadcrumbs/templates/breadcrumbs/partial/breadcrumb.html create mode 100644 breadcrumbs/templatetags/__init__.py create mode 100644 breadcrumbs/templatetags/breadcrumb_tags.py create mode 100644 breadcrumbs_sample/templatetag/__init__.py create mode 100644 breadcrumbs_sample/templatetag/models.py create mode 100644 breadcrumbs_sample/templatetag/templates/dynamic.html create mode 100644 breadcrumbs_sample/templatetag/templates/index.html create mode 100644 breadcrumbs_sample/templatetag/templates/unpacking.html create mode 100644 breadcrumbs_sample/templatetag/tests.py create mode 100644 breadcrumbs_sample/templatetag/views.py diff --git a/.gitignore b/.gitignore index 6138897..bc36f37 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ *.pyc .*.sw* build +.idea/ +breadcrumbs_sample/test.db \ No newline at end of file diff --git a/breadcrumbs/breadcrumbs.py b/breadcrumbs/breadcrumbs.py index 9c4575d..f19ef8c 100644 --- a/breadcrumbs/breadcrumbs.py +++ b/breadcrumbs/breadcrumbs.py @@ -7,6 +7,9 @@ from django.utils.translation import ugettext as _ from django.utils.safestring import mark_safe +BREADCRUMBS_AUTO_HOME = getattr(settings, 'BREADCRUMBS_AUTO_HOME', False) +BREADCRUMBS_HOME_TITLE = getattr(settings, 'BREADCRUMBS_HOME_TITLE', _(u'Home')) + class BreadcrumbsInvalidFormat(Exception): """ @@ -66,7 +69,7 @@ class Breadcrumbs(Singleton): class or with get_breadcrumbs(). """ __bds = [] - __autohome = getattr(settings, 'BREADCRUMBS_AUTO_HOME', False) + __autohome = BREADCRUMBS_AUTO_HOME __urls = [] __started = False @@ -78,12 +81,12 @@ def __call__(self, *args, **kwargs): def __fill_home(self): # fill home if settings.BREADCRUMBS_AUTO_HOME is True if self.__autohome and len(self.__bds) == 0: - home_title = getattr(settings, 'BREADCRUMBS_HOME_TITLE', _(u'Home')) + home_title = BREADCRUMBS_HOME_TITLE self.__fill_bds((home_title, u"/")) def _clean(self): self.__bds = [] - self.__autohome = getattr(settings, 'BREADCRUMBS_AUTO_HOME', False) + self.__autohome = BREADCRUMBS_AUTO_HOME self.__urls = [] self.__fill_home() diff --git a/breadcrumbs/templates/breadcrumbs/partial/breadcrumb.html b/breadcrumbs/templates/breadcrumbs/partial/breadcrumb.html new file mode 100644 index 0000000..28c7e4c --- /dev/null +++ b/breadcrumbs/templates/breadcrumbs/partial/breadcrumb.html @@ -0,0 +1,12 @@ + \ No newline at end of file diff --git a/breadcrumbs/templatetags/__init__.py b/breadcrumbs/templatetags/__init__.py new file mode 100644 index 0000000..130f862 --- /dev/null +++ b/breadcrumbs/templatetags/__init__.py @@ -0,0 +1,5 @@ +#! coding: utf-8 + + + +__author__ = 'lgomez' diff --git a/breadcrumbs/templatetags/breadcrumb_tags.py b/breadcrumbs/templatetags/breadcrumb_tags.py new file mode 100644 index 0000000..a077c4b --- /dev/null +++ b/breadcrumbs/templatetags/breadcrumb_tags.py @@ -0,0 +1,110 @@ +#! coding: utf-8 +from django import template + +register = template.Library() + + +#http://stackoverflow.com/questions/4356329/creating-a-python-dictionary-from-a-line-of-text/4356415#4356415 +def pairwise(iterable): + #s -> (s0,s1), (s2,s3), (s4, s5), ... + a = iter(iterable) + return zip(a, a) + + +@register.inclusion_tag('breadcrumbs/partial/breadcrumb.html', takes_context=True) +def breadcrumbs(context, *args, **kwargs): + """ + This tag renders all breadcrumbs registered. + But you can pass some arguments too. + + If you pass one parameter, it will be shown without an anchor, just what you write. + i.e.: + {% breadcrumb "profile" %} or {% breadcrumb my_context_var %} will print + each breadcrumb registered and "profile" or what is in 'my_context_var' variable. + + e.g.: Registering two breadcrumb (see "utils.py" module): + + {% breadcrumb "profile" %} + => + breadcrumb_1 > + breadcrumb_2 > + profile > + + If you pass more that one parameter, it takes in pairs. The first must be the what you + want to show in the breadcrumb, and the second the url. If you pass a odd number of + parameters, the last must be a "name". + i.e.: You can do: + {% breadcrumb "my foos" list_link %} and + {% breadcrumb "my foos" list_link "foo_settings" %} and + {% breadcrumb "my foos" list_link "that foo" foo_url %} and + {% breadcrumb "my foos" list_link "that foo" foo_url "foo_settings" %} and so on + + e.g.: For readability I supposed no another breadcrumbs, just what I wrote here. + But you can register breadcrumb and they will be shown before that: + + {% url "foo_detail" foo.id as foo_url %} + {% url "foo_list" as list %} + {% breadcrumb "my foos" list "that foo" foo_url "foo_settings" %} + => + my foos > + that foo > + "foo_settings" > + + If you pass the kwarg "unpack" with value True, the template tag only takes 2 arguments. + the first a iterable that contains tuple of (name, url,), and the second a extra argument, + Thar will be shown (just a "name") + i.e.: + {% breadcrumb my_context_var unpack=True %} or + {% breadcrumb my_context_var "settings_foo" unpack=True %} + + e.g.: + In some class-based view: + # ... + + class FooSettings(DetailView): + model = Foo + template = "foo_settings.html" + + def get_context_data(self, **kwargs): + context = super(FooSettings, self).get_context_data(**kwargs) + context["list"] = ("my_foos", reverse("foos"),), ("foo", reverse("foo", args=[self.object.id,]),) + return context + + # ... + + In "foo_settings.html" template: + + {% breadcrumb list unpack=True %} + + """ + template_context = dict() + unpack = kwargs.get('unpack', False) + args_list = list(args) + extras = [] + extra = None + args_len = len(args_list) + + if unpack: + if args_len == 0: + raise TypeError("Tag breadcrumb takes at least one argument with 'unpack=True' option.") + iterable = args_list.pop(0) + try: + for arg in iterable: + extras.append(arg) + except TypeError as e: + raise TypeError("Tag breadcrumbs take a iterable like first parameter with 'unpack=True'. %s" % e) + args_len = len(args_list) + + if args_len % 2 != 0: + extra = args_list.pop(-1) + + for name, url in pairwise(args_list): + extras.append((name, url)) + + template_context['breadcrumbs'] = context['request'].breadcrumbs + template_context['extras'] = extras + template_context['extra'] = extra + return template_context + + +__author__ = 'lgomez' diff --git a/breadcrumbs/utils.py b/breadcrumbs/utils.py index 350343f..85d089a 100644 --- a/breadcrumbs/utils.py +++ b/breadcrumbs/utils.py @@ -4,6 +4,51 @@ from breadcrumbs import Breadcrumbs, BreadcrumbsNotSet from django.conf import settings from django.core.cache import cache +from breadcrumbs import BREADCRUMBS_AUTO_HOME, BREADCRUMBS_HOME_TITLE +from django.utils.translation import ugettext as _ +import re + +BREADCRUMBS_AUTO_HOME = getattr(settings, 'BREADCRUMBS_AUTO_HOME', False) +BREADCRUMBS_HOME_TITLE = getattr(settings, 'BREADCRUMBS_HOME_TITLE', _(u'Home')) + +PAGE_MATCHES = getattr(settings, 'PAGE_MATCHES', dict()) +#This must be a dictionary. The key are used like regular expression to match the url. +# The value will be shown in breadcrumb. See the template. +# PAGE_MATCHES = { +# r'/': u"Home", +# r'/foo/': u"Foo page" +# } + + +if BREADCRUMBS_AUTO_HOME: + PAGE_MATCHES.update({r'/': BREADCRUMBS_HOME_TITLE}) + + +def register_referer(request): + """ + In any View, you can register the page where you come from. + It will be automatically matched PAGE_MATCHES with dictionary. + If it doesn't match, it wont be added to breadcrumbs + """ + referer = get_referrer(request) + if referer: + name = get_name_from_url(referer) + if name and (name != BREADCRUMBS_HOME_TITLE): + request.breadcrumbs(name, referer) + + +def get_referrer(request): + return request.META.get('HTTP_REFERER', None) + + +def get_name_from_url(url): + """ + If the url matched with any regex, then return the name of that page. + """ + for page_regex in PAGE_MATCHES: + if re.search(page_regex, url): + return PAGE_MATCHES[page_regex] + return None def make_flatpages_cache_key(): diff --git a/breadcrumbs_sample/settings.py b/breadcrumbs_sample/settings.py index 23609fb..9911402 100644 --- a/breadcrumbs_sample/settings.py +++ b/breadcrumbs_sample/settings.py @@ -105,7 +105,9 @@ 'django.contrib.flatpages', # Uncomment the next line to enable the admin: 'django.contrib.admin', - 'breadcrumbs_sample.webui' + 'breadcrumbs_sample.webui', + 'templatetag', + 'breadcrumbs', ) BREADCRUMBS_AUTO_HOME = True diff --git a/breadcrumbs_sample/templatetag/__init__.py b/breadcrumbs_sample/templatetag/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/breadcrumbs_sample/templatetag/models.py b/breadcrumbs_sample/templatetag/models.py new file mode 100644 index 0000000..71a8362 --- /dev/null +++ b/breadcrumbs_sample/templatetag/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/breadcrumbs_sample/templatetag/templates/dynamic.html b/breadcrumbs_sample/templatetag/templates/dynamic.html new file mode 100644 index 0000000..08b7f85 --- /dev/null +++ b/breadcrumbs_sample/templatetag/templates/dynamic.html @@ -0,0 +1,11 @@ +{% extends "index.html" %} +{% load breadcrumb_tags %} + +{% block content %} + {% url "tag-index" as index_url %} + + {% breadcrumbs "tag-index-page" index_url "dynamic-breadcrumb" %} + +

You are generating dynamic breadcrumbs

+ You can click on them! +{% endblock content %} \ No newline at end of file diff --git a/breadcrumbs_sample/templatetag/templates/index.html b/breadcrumbs_sample/templatetag/templates/index.html new file mode 100644 index 0000000..d37967d --- /dev/null +++ b/breadcrumbs_sample/templatetag/templates/index.html @@ -0,0 +1,26 @@ +{% load breadcrumb_tags %} + + + + + + +{% block content %} + {% breadcrumbs "breadcrumb-tag-index" %} + +

You are on breadcrumb template tag page

+ Click on some link and you will see the "index" breadcrumb. +{% endblock content %} + +
+
Tag index page
+
+ +
Dynamic page and url
+
+ +
Unpack of first parameter
+
+ + + \ No newline at end of file diff --git a/breadcrumbs_sample/templatetag/templates/unpacking.html b/breadcrumbs_sample/templatetag/templates/unpacking.html new file mode 100644 index 0000000..f349d00 --- /dev/null +++ b/breadcrumbs_sample/templatetag/templates/unpacking.html @@ -0,0 +1,10 @@ +{% extends "index.html" %} +{% load breadcrumb_tags %} + +{% block content %} + + {% breadcrumbs extra_params "unpacking-breadcrumb" unpack=True %} + +

You are unpack breadcrumbs

+ You can click on them! +{% endblock content %} \ No newline at end of file diff --git a/breadcrumbs_sample/templatetag/tests.py b/breadcrumbs_sample/templatetag/tests.py new file mode 100644 index 0000000..501deb7 --- /dev/null +++ b/breadcrumbs_sample/templatetag/tests.py @@ -0,0 +1,16 @@ +""" +This file demonstrates writing tests using the unittest module. These will pass +when you run "manage.py test". + +Replace this with more appropriate tests for your application. +""" + +from django.test import TestCase + + +class SimpleTest(TestCase): + def test_basic_addition(self): + """ + Tests that 1 + 1 always equals 2. + """ + self.assertEqual(1 + 1, 2) diff --git a/breadcrumbs_sample/templatetag/views.py b/breadcrumbs_sample/templatetag/views.py new file mode 100644 index 0000000..91e16c7 --- /dev/null +++ b/breadcrumbs_sample/templatetag/views.py @@ -0,0 +1,29 @@ +# Create your views here. +from django.views.generic import TemplateView +from breadcrumbs.utils import register_referer + + +class IncludeReferer(TemplateView): + def get_context_data(self, **kwargs): + context = super(IncludeReferer, self).get_context_data(**kwargs) + register_referer(self.request) # Including the referer if it exists + return context + + +class IncludingDynamicURLs(IncludeReferer): + template_name = "dynamic.html" + pass + + +class UnpackingAVariableAndMore(IncludeReferer): + template_name = "unpacking.html" + + def get_context_data(self, **kwargs): + context = super(UnpackingAVariableAndMore, self).get_context_data(**kwargs) + extra_params = ("name1", "example.com"), ("name2", "example2.com") + context["extra_params"] = extra_params + return context + + +class Index(TemplateView): + template_name = "index.html" \ No newline at end of file diff --git a/breadcrumbs_sample/test.db b/breadcrumbs_sample/test.db index 52259d8eccfb297bc30dd5c797bad46ebebb2a2a..3ddab932f2e952d08258cccf39ab9ca73dedc4cd 100644 GIT binary patch delta 237 zcmZp8!PM}AX@WFsAOiz~?nDK9AVc?&>c*4>{v1q9lNgwVnI>&)Y-6ggXJ++nqjs0C*EBvbbGX33M4gEuWjr_tRtD>?pa($}`9Ub!wD;$GOY>f;IjdcwybPX*P z49u;J%&iQ}^$d)ROqt9LCkqF^;|98tiFq3X^ET$&n*~``F;CtWuBxiS?8`{VVa$sn FVgPpdNl*X) delta 84 zcmZp8!PM}AX@WGXKLZd