Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Fixed #14516 -- Extract methods from removetags and slugify template …

…filters

Patch by @jphalip updated to apply, documentation and release notes
added.

I've documented strip_tags as well as remove_tags as the difference
between the two wouldn't be immediately obvious.
  • Loading branch information...
commit 212b9826bdda5c3c2eb680e6f9c5b046b4172300 1 parent 58683e9
Marc Tamlyn mjtamlyn authored andrewgodwin committed
10 django/template/defaultfilters.py
View
@@ -231,12 +231,12 @@ def make_list(value):
@stringfilter
def slugify(value):
"""
- Normalizes string, converts to lowercase, removes non-alpha characters,
- and converts spaces to hyphens.
+ Converts to lowercase, removes non-word characters (alphanumerics and
+ underscores) and converts spaces to hyphens. Also strips leading and
+ trailing whitespace.
"""
- value = unicodedata.normalize('NFKD', value).encode('ascii', 'ignore').decode()
- value = re.sub('[^\w\s-]', '', value).strip().lower()
- return mark_safe(re.sub('[-\s]+', '-', value))
+ from django.utils.text import slugify
+ return slugify(value)
@register.filter(is_safe=True)
def stringformat(value, arg):
11 django/utils/html.py
View
@@ -123,6 +123,17 @@ def strip_tags(value):
return re.sub(r'<[^>]*?>', '', force_text(value))
strip_tags = allow_lazy(strip_tags)
+def remove_tags(html, tags):
+ """Returns the given HTML with given tags removed."""
+ tags = [re.escape(tag) for tag in tags.split()]
+ tags_re = u'(%s)' % u'|'.join(tags)
+ starttag_re = re.compile(ur'<%s(/?>|(\s+[^>]*>))' % tags_re, re.U)
+ endtag_re = re.compile(u'</%s>' % tags_re)
+ html = starttag_re.sub(u'', html)
+ html = endtag_re.sub(u'', html)
+ return html
+remove_tags = allow_lazy(remove_tags, unicode)
+
def strip_spaces_between_tags(value):
"""Returns the given HTML with spaces between tags removed."""
return re.sub(r'>\s+<', '><', force_text(value))
12 django/utils/text.py
View
@@ -16,6 +16,7 @@
from django.utils.functional import allow_lazy, SimpleLazyObject
from django.utils import six
from django.utils.translation import ugettext_lazy, ugettext as _, pgettext
+from django.utils.safestring import mark_safe
# Capitalizes the first letter of a string.
capfirst = lambda x: x and force_text(x)[0].upper() + force_text(x)[1:]
@@ -383,3 +384,14 @@ def unescape_string_literal(s):
quote = s[0]
return s[1:-1].replace(r'\%s' % quote, quote).replace(r'\\', '\\')
unescape_string_literal = allow_lazy(unescape_string_literal)
+
+def slugify(value):
+ """
+ Converts to lowercase, removes non-word characters (alphanumerics and
+ underscores) and converts spaces to hyphens. Also strips leading and
+ trailing whitespace.
+ """
+ value = unicodedata.normalize('NFKD', value).encode('ascii', 'ignore')
+ value = unicode(re.sub('[^\w\s-]', '', value).strip().lower())
+ return mark_safe(re.sub('[-\s]+', '-', value))
+slugify = allow_lazy(slugify, unicode)
45 docs/ref/utils.txt
View
@@ -486,6 +486,33 @@ escaping HTML.
through :func:`conditional_escape` which (ultimately) calls
:func:`~django.utils.encoding.force_text` on the values.
+.. function:: strip_tags(value)
+
+ Removes anything that looks like an html tag from the string, that is
+ anything contained within ``<>``.
+
+ For example::
+
+ strip_tags(value)
+
+ If ``value`` is ``"<b>Joel</b> <button>is</button> a <span>slug</span>"`` the
+ return value will be ``"Joel is a slug"``.
+
+.. function:: remove_tags(value, tags)
+
+ Removes a list of [X]HTML tag names from the output.
+
+ For example::
+
+ remove_tags(value, ["b", "span"])
+
+ If ``value`` is ``"<b>Joel</b> <button>is</button> a <span>slug</span>"`` the
+ return value will be ``"Joel <button>is</button> a slug"``.
+
+ Note that this filter is case-sensitive.
+
+ If ``value`` is ``"<B>Joel</B> <button>is</button> a <span>slug</span>"`` the
+ return value will be ``"<B>Joel</B> <button>is</button> a slug"``.
.. _str.format: http://docs.python.org/library/stdtypes.html#str.format
@@ -599,6 +626,24 @@ appropriate entities.
Can be called multiple times on a single string (the resulting escaping is
only applied once).
+``django.utils.text``
+=====================
+
+.. module:: django.utils.text
+ :synopsis: Text manipulation.
+
+.. function:: slugify
+
+ Converts to lowercase, removes non-word characters (alphanumerics and
+ underscores) and converts spaces to hyphens. Also strips leading and trailing
+ whitespace.
+
+ For example::
+
+ slugify(value)
+
+ If ``value`` is ``"Joel is a slug"``, the output will be ``"joel-is-a-slug"``.
+
``django.utils.translation``
============================
4 docs/releases/1.5.txt
View
@@ -267,6 +267,10 @@ Miscellaneous
* :func:`~django.utils.http.int_to_base36` properly raises a :exc:`TypeError`
instead of :exc:`ValueError` for non-integer inputs.
+* The ``slugify`` template filter is now available as a standard python
+ function at :func:`django.utils.text.slugify`. Similarly, ``remove_tags`` is
+ available at :func:`django.utils.html.remove_tags`.
+
Features deprecated in 1.5
==========================
9 tests/regressiontests/utils/html.py
View
@@ -146,3 +146,12 @@ def test_clean_html(self):
)
for value, output in items:
self.check_output(f, value, output)
+
+ def test_remove_tags(self):
+ f = html.remove_tags
+ items = (
+ ("<b><i>Yes</i></b>", "b i", "Yes"),
+ ("<a>x</a> <p><b>y</b></p>", "a b", "x <p>y</p>"),
+ )
+ for value, tags, output in items:
+ self.assertEquals(f(value, tags), output)
8 tests/regressiontests/utils/text.py
View
@@ -113,3 +113,11 @@ def test_wrap(self):
self.assertEqual(text.wrap(long_word, 20), long_word)
self.assertEqual(text.wrap('a %s word' % long_word, 10),
'a\n%s\nword' % long_word)
+
+ def test_slugify(self):
+ items = (
+ (u'Hello, World!', 'hello-world'),
+ (u'spam & eggs', 'spam-eggs'),
+ )
+ for value, output in items:
+ self.assertEqual(text.slugify(value), output)
Please sign in to comment.
Something went wrong with that request. Please try again.