Skip to content

Commit ca6b1c8

Browse files
committed
Add option include_time to LocalizedUniqueSlugField
1 parent 64c3c06 commit ca6b1c8

File tree

4 files changed

+63
-10
lines changed

4 files changed

+63
-10
lines changed

README.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,15 @@ Besides ``LocalizedField``, there's also:
212212
title = LocalizedField()
213213
slug = LocalizedUniqueSlugField(populate_from='title')
214214
215+
By setting the option ``include_time=True``
216+
217+
.. code-block:: python
218+
219+
slug = LocalizedUniqueSlugField(populate_from='title', include_time=True)
220+
221+
You can instruct the field to include a part of the current time into
222+
the resulting slug. This is useful if you're running into a lot of collisions.
223+
215224
* ``LocalizedAutoSlugField``
216225
Automatically creates a slug for every language from the specified field.
217226

localized_fields/fields/localized_autoslug_field.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from typing import Callable
2+
from datetime import datetime
23

34
from django import forms
45
from django.conf import settings
@@ -16,6 +17,7 @@ def __init__(self, *args, **kwargs):
1617
"""Initializes a new instance of :see:LocalizedAutoSlugField."""
1718

1819
self.populate_from = kwargs.pop('populate_from', None)
20+
self.include_time = kwargs.pop('include_time', False)
1921

2022
super(LocalizedAutoSlugField, self).__init__(
2123
*args,
@@ -30,6 +32,7 @@ def deconstruct(self):
3032
LocalizedAutoSlugField, self).deconstruct()
3133

3234
kwargs['populate_from'] = self.populate_from
35+
kwargs['include_time'] = self.include_time
3336
return name, path, args, kwargs
3437

3538
def formfield(self, **kwargs):
@@ -76,6 +79,9 @@ def pre_save(self, instance, add: bool):
7679
if not value:
7780
continue
7881

82+
if self.include_time:
83+
value += '-%s' % datetime.now().microsecond
84+
7985
def is_unique(slug: str, language: str) -> bool:
8086
"""Gets whether the specified slug is unique."""
8187

localized_fields/fields/localized_uniqueslug_field.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
from ..localized_value import LocalizedValue
88
from .localized_autoslug_field import LocalizedAutoSlugField
99

10+
from datetime import datetime
11+
1012

1113
class LocalizedUniqueSlugField(LocalizedAutoSlugField):
1214
"""Automatically provides slugs for a localized
@@ -34,6 +36,18 @@ def __init__(self, *args, **kwargs):
3436
)
3537

3638
self.populate_from = kwargs.pop('populate_from')
39+
self.use_time = kwargs.pop('include_time', False)
40+
41+
def deconstruct(self):
42+
"""Deconstructs the field into something the database
43+
can store."""
44+
45+
name, path, args, kwargs = super(
46+
LocalizedUniqueSlugField, self).deconstruct()
47+
48+
kwargs['populate_from'] = self.populate_from
49+
kwargs['include_time'] = self.include_time
50+
return name, path, args, kwargs
3751

3852
def pre_save(self, instance, add: bool):
3953
"""Ran just before the model is saved, allows us to built
@@ -70,6 +84,9 @@ def pre_save(self, instance, add: bool):
7084
continue
7185

7286
slug = slugify(value, allow_unicode=True)
87+
if self.include_time:
88+
slug += '-%d' % datetime.now().microsecond
89+
7390
if instance.retries > 0:
7491
slug += '-%d' % instance.retries
7592

tests/test_localized_slug_fields.py

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -43,30 +43,51 @@ def test_populate_auto(cls):
4343
cls._test_populate(cls.AutoSlugModel)
4444

4545
@classmethod
46-
def test_populate_magic(cls):
46+
def test_populate_unique(cls):
4747
cls._test_populate(cls.MagicSlugModel)
4848

4949
@classmethod
5050
def test_populate_multiple_languages_auto(cls):
5151
cls._test_populate_multiple_languages(cls.AutoSlugModel)
5252

5353
@classmethod
54-
def test_populate_multiple_languages_magic(cls):
54+
def test_populate_multiple_languages_unique(cls):
5555
cls._test_populate_multiple_languages(cls.MagicSlugModel)
5656

5757
@classmethod
5858
def test_unique_slug_auto(cls):
5959
cls._test_unique_slug(cls.AutoSlugModel)
6060

6161
@classmethod
62-
def test_unique_slug_magic(cls):
62+
def test_unique_slug_unique(cls):
6363
cls._test_unique_slug(cls.MagicSlugModel)
6464

65-
def test_unique_slug_magic_max_retries(self):
66-
"""Tests whether the magic slug implementation doesn't
65+
@staticmethod
66+
def test_unique_slug_with_time():
67+
"""Tests whether the primary key is included in
68+
the slug when the 'use_pk' option is enabled."""
69+
70+
title = 'myuniquetitle'
71+
72+
PkModel = get_fake_model(
73+
'PkModel',
74+
{
75+
'title': LocalizedField(),
76+
'slug': LocalizedUniqueSlugField(populate_from='title', include_time=True)
77+
}
78+
)
79+
80+
obj = PkModel()
81+
obj.title.en = title
82+
obj.save()
83+
84+
assert obj.slug.en.startswith('%s-' % title)
85+
86+
def test_unique_slug_unique_max_retries(self):
87+
"""Tests whether the unique slug implementation doesn't
6788
try to find a slug forever and gives up after a while."""
6889

69-
title = 'mymagictitle'
90+
title = 'myuniquetitle'
7091

7192
obj = self.MagicSlugModel()
7293
obj.title.en = title
@@ -83,23 +104,23 @@ def test_unique_slug_utf_auto(cls):
83104
cls._test_unique_slug_utf(cls.AutoSlugModel)
84105

85106
@classmethod
86-
def test_unique_slug_utf_magic(cls):
107+
def test_unique_slug_utf_unique(cls):
87108
cls._test_unique_slug_utf(cls.MagicSlugModel)
88109

89110
@classmethod
90111
def test_deconstruct_auto(cls):
91112
cls._test_deconstruct(LocalizedAutoSlugField)
92113

93114
@classmethod
94-
def test_deconstruct_magic(cls):
115+
def test_deconstruct_unique(cls):
95116
cls._test_deconstruct(LocalizedUniqueSlugField)
96117

97118
@classmethod
98119
def test_formfield_auto(cls):
99120
cls._test_formfield(LocalizedAutoSlugField)
100121

101122
@classmethod
102-
def test_formfield_magic(cls):
123+
def test_formfield_unique(cls):
103124
cls._test_formfield(LocalizedUniqueSlugField)
104125

105126
@staticmethod
@@ -130,7 +151,7 @@ def _test_populate_multiple_languages(model):
130151
def _test_unique_slug(model):
131152
"""Tests whether unique slugs are properly generated."""
132153

133-
title = 'mymagictitle'
154+
title = 'myuniquetitle'
134155

135156
obj = model()
136157
obj.title.en = title

0 commit comments

Comments
 (0)