Merge pull request #418 from nephila/hotfix/slug_clean
Generate valid slug in wizard if the given one is taken
This commit is contained in:
commit
7cd9294adc
4 changed files with 88 additions and 13 deletions
|
@ -8,10 +8,10 @@ from cms.wizards.wizard_base import Wizard
|
|||
from cms.wizards.wizard_pool import AlreadyRegisteredException, wizard_pool
|
||||
from django import forms
|
||||
from django.conf import settings
|
||||
from django.utils.text import slugify
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from .cms_appconfig import BlogConfig
|
||||
from .fields import slugify
|
||||
from .forms import PostAdminFormBase
|
||||
from .models import Post
|
||||
|
||||
|
@ -19,6 +19,11 @@ from .models import Post
|
|||
class PostWizardForm(PostAdminFormBase):
|
||||
default_appconfig = None
|
||||
|
||||
slug = forms.SlugField(
|
||||
label=_('Slug'), max_length=767, required=False,
|
||||
help_text=_('Leave empty for automatic slug, or override as required.'),
|
||||
)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
if 'initial' not in kwargs or not kwargs.get('initial', False):
|
||||
kwargs['initial'] = {}
|
||||
|
@ -36,7 +41,7 @@ class PostWizardForm(PostAdminFormBase):
|
|||
|
||||
class Meta:
|
||||
model = Post
|
||||
fields = ['app_config', 'title', 'abstract', 'categories']
|
||||
fields = ['app_config', 'title', 'slug', 'abstract', 'categories']
|
||||
|
||||
class Media:
|
||||
js = ('admin/js/jquery.js', 'admin/js/jquery.init.js',)
|
||||
|
@ -45,6 +50,23 @@ class PostWizardForm(PostAdminFormBase):
|
|||
self.instance._set_default_author(get_current_user())
|
||||
return super(PostWizardForm, self).save(commit)
|
||||
|
||||
def clean_slug(self):
|
||||
"""
|
||||
Generate a valid slug, in case the given one is taken
|
||||
"""
|
||||
source = self.cleaned_data.get('slug', '')
|
||||
lang_choice = self.language_code
|
||||
if not source:
|
||||
source = slugify(self.cleaned_data.get('title', ''))
|
||||
qs = Post._default_manager.active_translations(lang_choice).language(lang_choice)
|
||||
used = list(qs.values_list('translations__slug', flat=True))
|
||||
slug = source
|
||||
i = 1
|
||||
while slug in used:
|
||||
slug = '%s-%s' % (source, i)
|
||||
i += 1
|
||||
return slug
|
||||
|
||||
|
||||
class PostWizard(Wizard):
|
||||
pass
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import absolute_import, print_function, unicode_literals
|
||||
|
||||
import django
|
||||
from django.db.models import SlugField
|
||||
from django.utils.text import slugify as django_slugify
|
||||
|
||||
__all__ = ['AutoSlugField']
|
||||
|
||||
|
@ -7,3 +12,10 @@ class AutoSlugField(SlugField):
|
|||
def __init__(self, *args, **kwargs):
|
||||
self.allow_unicode = kwargs.pop('allow_unicode', False)
|
||||
super(SlugField, self).__init__(*args, **kwargs)
|
||||
|
||||
|
||||
def slugify(base):
|
||||
if django.VERSION >= (1, 9):
|
||||
return django_slugify(base, allow_unicode=True)
|
||||
else:
|
||||
return django_slugify(base)
|
||||
|
|
|
@ -3,7 +3,6 @@ from __future__ import absolute_import, print_function, unicode_literals
|
|||
|
||||
import hashlib
|
||||
|
||||
import django
|
||||
from aldryn_apphooks_config.fields import AppHookConfigField
|
||||
from aldryn_apphooks_config.managers.parler import AppHookConfigTranslatableManager
|
||||
from cms.models import CMSPlugin, PlaceholderField
|
||||
|
@ -19,7 +18,6 @@ from django.utils import timezone
|
|||
from django.utils.encoding import force_bytes, force_text, python_2_unicode_compatible
|
||||
from django.utils.functional import cached_property
|
||||
from django.utils.html import escape, strip_tags
|
||||
from django.utils.text import slugify
|
||||
from django.utils.translation import get_language, ugettext_lazy as _
|
||||
from djangocms_text_ckeditor.fields import HTMLField
|
||||
from filer.fields.image import FilerImageField
|
||||
|
@ -30,7 +28,7 @@ from sortedm2m.fields import SortedManyToManyField
|
|||
from taggit_autosuggest.managers import TaggableManager
|
||||
|
||||
from .cms_appconfig import BlogConfig
|
||||
from .fields import AutoSlugField
|
||||
from .fields import AutoSlugField, slugify
|
||||
from .managers import GenericDateTaggedManager
|
||||
from .settings import get_setting
|
||||
|
||||
|
@ -47,7 +45,6 @@ thumbnail_model = '%s.%s' % (
|
|||
ThumbnailOption._meta.app_label, ThumbnailOption.__name__
|
||||
)
|
||||
|
||||
|
||||
try:
|
||||
from knocker.mixins import KnockerModel
|
||||
except ImportError:
|
||||
|
@ -315,10 +312,7 @@ class Post(KnockerModel, BlogMetaMixin, TranslatableModel):
|
|||
if self.publish and self.date_published is None:
|
||||
self.date_published = timezone.now()
|
||||
if not self.slug and self.title:
|
||||
if django.VERSION >= (1, 9):
|
||||
self.slug = slugify(self.title, allow_unicode=True)
|
||||
else:
|
||||
self.slug = slugify(self.title)
|
||||
self.slug = slugify(self.title)
|
||||
super(Post, self).save(*args, **kwargs)
|
||||
|
||||
def save_translation(self, translation, *args, **kwargs):
|
||||
|
@ -349,9 +343,12 @@ class Post(KnockerModel, BlogMetaMixin, TranslatableModel):
|
|||
if '<day>' in urlconf:
|
||||
kwargs['day'] = '%02d' % current_date.day
|
||||
if '<slug>' in urlconf:
|
||||
kwargs['slug'] = self.safe_translation_getter('slug', language_code=lang, any_language=True) # NOQA
|
||||
kwargs['slug'] = self.safe_translation_getter(
|
||||
'slug', language_code=lang, any_language=True
|
||||
) # NOQA
|
||||
if '<category>' in urlconf:
|
||||
kwargs['category'] = category.safe_translation_getter('slug', language_code=lang, any_language=True) # NOQA
|
||||
kwargs['category'] = category.safe_translation_getter(
|
||||
'slug', language_code=lang, any_language=True) # NOQA
|
||||
return reverse('%s:post-detail' % self.app_config.namespace, kwargs=kwargs)
|
||||
|
||||
def get_title(self):
|
||||
|
@ -555,7 +552,6 @@ class AuthorEntriesPlugin(BasePostPlugin):
|
|||
|
||||
@python_2_unicode_compatible
|
||||
class GenericBlogPlugin(BasePostPlugin):
|
||||
|
||||
class Meta:
|
||||
abstract = False
|
||||
|
||||
|
|
|
@ -82,6 +82,51 @@ class WizardTest(BaseTest):
|
|||
instance = form.save()
|
||||
self.assertEqual(instance.author, self.user_normal)
|
||||
|
||||
def test_wizard_duplicate_slug(self):
|
||||
from cms.utils.permissions import current_user
|
||||
from cms.wizards.wizard_pool import wizard_pool
|
||||
from djangocms_blog.models import Post
|
||||
self.get_pages()
|
||||
cat_2 = BlogCategory.objects.create(name='category 1 - blog 2', app_config=self.app_config_2)
|
||||
|
||||
with current_user(self.user_staff):
|
||||
wiz = None
|
||||
for wiz in wizard_pool.get_entries():
|
||||
if wiz.model == Post and wiz.title == 'New Blog':
|
||||
break
|
||||
form = wiz.form(data={
|
||||
'1-title': 'title article',
|
||||
'1-abstract': 'abstract article',
|
||||
'1-categories': [self.category_1.pk],
|
||||
}, prefix=1)
|
||||
self.assertEqual(form.default_appconfig, self.app_config_1.pk)
|
||||
self.assertTrue(form.is_valid())
|
||||
instance1 = form.save()
|
||||
self.assertEqual(instance1.slug, 'title-article')
|
||||
|
||||
form = wiz.form(data={
|
||||
'1-title': 'title article',
|
||||
'1-abstract': 'abstract article',
|
||||
'1-categories': [self.category_1.pk],
|
||||
}, prefix=1)
|
||||
self.assertEqual(form.default_appconfig, self.app_config_1.pk)
|
||||
self.assertTrue(form.is_valid())
|
||||
instance2 = form.save()
|
||||
self.assertEqual(instance2.slug, 'title-article-1')
|
||||
|
||||
for wiz in wizard_pool.get_entries():
|
||||
if wiz.model == Post and wiz.title == 'New Article':
|
||||
break
|
||||
form = wiz.form(data={
|
||||
'1-title': 'title article',
|
||||
'1-abstract': 'abstract article',
|
||||
'1-categories': [cat_2.pk],
|
||||
}, prefix=1)
|
||||
self.assertEqual(form.default_appconfig, self.app_config_2.pk)
|
||||
self.assertTrue(form.is_valid())
|
||||
instance3 = form.save()
|
||||
self.assertEqual(instance3.slug, 'title-article-2')
|
||||
|
||||
def test_wizard_init_categories_check(self):
|
||||
from cms.utils.permissions import current_user
|
||||
from cms.wizards.wizard_pool import wizard_pool
|
||||
|
|
Loading…
Reference in a new issue