Browse Source

OSCAR_SLUG_FUNCTION: Support string notation to set slugifier

Importing things in settings is discouraged. But until now,
OSCAR_SLUG_FUNCTION could only be set as a callable, which requires
importing. It's now been updated to use the import_string function.
master
Maik Hoepfel 11 years ago
parent
commit
76c7dac599
4 changed files with 43 additions and 13 deletions
  1. 9
    4
      docs/source/ref/settings.rst
  2. 2
    0
      docs/source/releases/v0.8.rst
  3. 20
    9
      oscar/core/utils.py
  4. 12
    0
      tests/unit/core/utils_tests.py

+ 9
- 4
docs/source/ref/settings.rst View File

@@ -158,7 +158,7 @@ A list of dashboard navigation elements. Usage is explained in
158 158
 ``OSCAR_DASHBOARD_DEFAULT_ACCESS_FUNCTION``
159 159
 -------------------------------------------
160 160
 
161
-Default: ``oscar.apps.dashboard.nav.default_access_fn``
161
+Default: ``'oscar.apps.dashboard.nav.default_access_fn'``
162 162
 
163 163
 ``OSCAR_DASHBOARD_NAVIGATION`` allows passing an access function for each node
164 164
 which is used to determine whether to show the node for a specific user or not.
@@ -452,17 +452,22 @@ stripped.  For instance::
452 452
 ``OSCAR_SLUG_FUNCTION``
453 453
 -----------------------
454 454
 
455
-Default: ``django.template.defaultfilters.slugify``
455
+Default: ``'oscar.core.utils.default_slugifier'``
456 456
 
457 457
 The slugify function to use.  Note that is used within Oscar's slugify wrapper
458
-(in ``oscar.core.utils``) which applies the custom map and blacklist.
458
+(in ``oscar.core.utils``) which applies the custom map and blacklist. String
459
+notation is recommended, but specifying a callable is supported for
460
+backwards-compatibility.
459 461
 
460 462
 Example::
461 463
 
464
+    # in myproject.utils
462 465
     def some_slugify(value)
463 466
         pass
464 467
 
465
-    OSCAR_SLUG_FUNCTION = some_slugify
468
+    # in settings.py
469
+    OSCAR_SLUG_FUNCTION = 'myproject.utils.some_slugify'
470
+
466 471
 
467 472
 ``OSCAR_SLUG_BLACKLIST``
468 473
 ------------------------

+ 2
- 0
docs/source/releases/v0.8.rst View File

@@ -101,6 +101,8 @@ Minor changes
101 101
   forgotten when adding tracking of the Python and Django version in 0.7.
102 102
   Total information collected now is the versions of Django, Python and Oscar.
103 103
 
104
+* ``OSCAR_SLUG_FUNCTION`` now accepts both string notation and a callable.
105
+
104 106
 Bugfixes
105 107
 ~~~~~~~~
106 108
 

+ 20
- 9
oscar/core/utils.py View File

@@ -1,11 +1,23 @@
1
-from __future__ import absolute_import  # for import below
2
-import six
1
+from __future__ import absolute_import  # for logging import below
3 2
 import logging
3
+import six
4 4
 
5 5
 from django.utils.timezone import get_current_timezone, is_naive, make_aware
6
-from unidecode import unidecode
7 6
 from django.conf import settings
8
-from django.template.defaultfilters import date as date_filter
7
+from django.template.defaultfilters import (date as date_filter,
8
+                                            slugify as django_slugify)
9
+from unidecode import unidecode
10
+
11
+from oscar.core.loading import import_string
12
+
13
+
14
+def default_slugifier(value):
15
+    """
16
+    Oscar's default slugifier function.
17
+    Uses Django's slugify function, but first applies unidecode() to convert
18
+    non-ASCII strings to ASCII equivalents where possible.
19
+    """
20
+    return django_slugify(value)
9 21
 
10 22
 
11 23
 def slugify(value):
@@ -18,11 +30,10 @@ def slugify(value):
18 30
         value = value.replace(k, v)
19 31
 
20 32
     # Allow an alternative slugify function to be specified
21
-    if hasattr(settings, 'OSCAR_SLUG_FUNCTION'):
22
-        slugifier = settings.OSCAR_SLUG_FUNCTION
23
-    else:
24
-        from django.template import defaultfilters
25
-        slugifier = defaultfilters.slugify
33
+    # Recommended way to specify a function is as a string
34
+    slugifier = getattr(settings, 'OSCAR_SLUG_FUNCTION', default_slugifier)
35
+    if isinstance(slugifier, six.string_types):
36
+        slugifier = import_string(slugifier)
26 37
 
27 38
     # Use unidecode to convert non-ASCII strings to ASCII equivalents where
28 39
     # possible.

+ 12
- 0
tests/unit/core/utils_tests.py View File

@@ -1,8 +1,11 @@
1
+# coding=utf-8
1 2
 from django.test import TestCase
2 3
 from django.test.utils import override_settings
3 4
 
4 5
 from oscar.core import utils
5 6
 
7
+sluggish = lambda s: s.upper()
8
+
6 9
 
7 10
 class TestSlugify(TestCase):
8 11
 
@@ -15,3 +18,12 @@ class TestSlugify(TestCase):
15 18
         blacklist = ['the']
16 19
         with override_settings(OSCAR_SLUG_BLACKLIST=blacklist):
17 20
             self.assertEqual('bible', utils.slugify('The Bible'))
21
+
22
+    def test_handles_unicode(self):
23
+        self.assertEqual('konig-der-strasse',
24
+                         utils.slugify(u'König der Straße'))
25
+
26
+    def test_works_with_custom_slugifier(self):
27
+        for fn in [sluggish, 'tests.unit.core.utils_tests.sluggish']:
28
+            with override_settings(OSCAR_SLUG_FUNCTION=fn):
29
+                self.assertEqual('HAM AND EGGS', utils.slugify('Ham and eggs'))

Loading…
Cancel
Save