在 Django 中保存一个(翻译的)slug 并使其独一无二是行不通的
In Django saving a (translated) slug and making it unique doesn't work
我使用 Django 1.11 和 parler 插件进行翻译。每次救一只鼻涕虫,我都想
- 测试它是否已经存在
- 截断 slug
- 加号
- 再次测试,如果新的 slug 存在等等
通过这种方式,我希望在保存时创建一个独特的 slug。
models.py:
from parler.models import TranslatableModel
from django.utils.translation import gettext_lazy as _
class Event(TranslatableModel):
translations = TranslatedFields(
event_title=models.CharField(_("event title"), max_length=512),
slug=models.SlugField(_("slug"), help_text=_("Used in the URL of the event page.")),
description=RichTextUploadingField(blank=True),
meta={'unique_together': (('language_code', 'slug'),)},
)
def save_translation(self, translation, *args, **kwargs):
"""Create a unique slug of 45 Characters + a dash and 4 digits."""
translation.slug = translation.slug[:50]
if Event.objects.active_translations(slug=translation.slug).exists():
# This is true on the first test for no apparent reason.
i = 0
while Event.objects.active_translations(slug=translation.slug).exists():
translation.slug = translation.slug[:44]+'-'+str(i)
i += 1
super(Event, self).save_translation(translation, *args, **kwargs)
此代码无效。它总是给 slug 添加一个数字,无论如何,即使我输入一个全新的 slug。
这里的问题是 save_translation 被多次调用。我的解决方案是:
def save_translation(self, translation, *args, **kwargs):
"""Create a unique slug build of the title + language code + a number."""
translation.slug = translation.slug[:50]
"""
This filter is a bit more complicated.
If the same slug but with a differen ID alread exists:
~Q(id=translation.master_id) &
Q(translations__slug=translation.slug)
Or if the same slug with the same ID but different language already exists:
Q(id=translation.master_id) &
~Q(translations__language_code=translation.language_code) &
Q(translations__slug=translation.slug)
"""
if Event.objects.filter(
(~Q(id=translation.master_id) &
Q(translations__slug=translation.slug)) |
(Q(id=translation.master_id) &
~Q(translations__language_code=translation.language_code) &
Q(translations__slug=translation.slug))
).exists():
i = 1
while Event.objects.filter(
(~Q(id=translation.master_id) &
Q(translations__slug=translation.slug)) |
(Q(id=translation.master_id) &
~Q(translations__language_code=translation.language_code) &
Q(translations__slug=translation.slug))
).exists():
# Truncate the slug, if it is too long. This happens, if the
# initial slug is to long or if the trailing number reaches
# another digit.
trunc_number = (4 + ceil(log10(i + 1)))
if len(translation.slug) + trunc_number > 50:
translation.slug = translation.slug[:50-trunc_number]
# Substitute the trailing language code and number with a bigger number.
translation.slug = re.sub(
r'(?P<slug_start>.*?)(-(de|en))?(-(\d)+)?$',
'\g<slug_start>' + '-' + translation.language_code + '-' + str(i),
translation.slug)
i += 1
super(Event, self).save_translation(translation, *args, **kwargs)
它比我希望的要长一些,但我认为它有效。
我使用 Django 1.11 和 parler 插件进行翻译。每次救一只鼻涕虫,我都想
- 测试它是否已经存在
- 截断 slug
- 加号
- 再次测试,如果新的 slug 存在等等
通过这种方式,我希望在保存时创建一个独特的 slug。
models.py:
from parler.models import TranslatableModel
from django.utils.translation import gettext_lazy as _
class Event(TranslatableModel):
translations = TranslatedFields(
event_title=models.CharField(_("event title"), max_length=512),
slug=models.SlugField(_("slug"), help_text=_("Used in the URL of the event page.")),
description=RichTextUploadingField(blank=True),
meta={'unique_together': (('language_code', 'slug'),)},
)
def save_translation(self, translation, *args, **kwargs):
"""Create a unique slug of 45 Characters + a dash and 4 digits."""
translation.slug = translation.slug[:50]
if Event.objects.active_translations(slug=translation.slug).exists():
# This is true on the first test for no apparent reason.
i = 0
while Event.objects.active_translations(slug=translation.slug).exists():
translation.slug = translation.slug[:44]+'-'+str(i)
i += 1
super(Event, self).save_translation(translation, *args, **kwargs)
此代码无效。它总是给 slug 添加一个数字,无论如何,即使我输入一个全新的 slug。
这里的问题是 save_translation 被多次调用。我的解决方案是:
def save_translation(self, translation, *args, **kwargs):
"""Create a unique slug build of the title + language code + a number."""
translation.slug = translation.slug[:50]
"""
This filter is a bit more complicated.
If the same slug but with a differen ID alread exists:
~Q(id=translation.master_id) &
Q(translations__slug=translation.slug)
Or if the same slug with the same ID but different language already exists:
Q(id=translation.master_id) &
~Q(translations__language_code=translation.language_code) &
Q(translations__slug=translation.slug)
"""
if Event.objects.filter(
(~Q(id=translation.master_id) &
Q(translations__slug=translation.slug)) |
(Q(id=translation.master_id) &
~Q(translations__language_code=translation.language_code) &
Q(translations__slug=translation.slug))
).exists():
i = 1
while Event.objects.filter(
(~Q(id=translation.master_id) &
Q(translations__slug=translation.slug)) |
(Q(id=translation.master_id) &
~Q(translations__language_code=translation.language_code) &
Q(translations__slug=translation.slug))
).exists():
# Truncate the slug, if it is too long. This happens, if the
# initial slug is to long or if the trailing number reaches
# another digit.
trunc_number = (4 + ceil(log10(i + 1)))
if len(translation.slug) + trunc_number > 50:
translation.slug = translation.slug[:50-trunc_number]
# Substitute the trailing language code and number with a bigger number.
translation.slug = re.sub(
r'(?P<slug_start>.*?)(-(de|en))?(-(\d)+)?$',
'\g<slug_start>' + '-' + translation.language_code + '-' + str(i),
translation.slug)
i += 1
super(Event, self).save_translation(translation, *args, **kwargs)
它比我希望的要长一些,但我认为它有效。