Repository: django-cms/django-cms

Issue:
KeyError 'slug' when trying to add a new page with the same slug as an already existing one
Reproduced this on django-cms 2.3.3

Steps to reproduce:
1. Create the first page with slug 'master' and publish it
2. Create the second page with the same slug ('master')
3. On the second page's change view tick 'Is published' and save the page

Expected:
- A nice error message that says that you can't have two published pages with the same slug

Actual:
- Status code 500,
  KeyError at /admin/cms/page/6/ 'slug'

Traceback:
File "/home/kux/workspace/src/other/django/django/core/handlers/base.py" in get_response
1.                         response = callback(request, _callback_args, *_callback_kwargs)
   File "/home/kux/workspace/src/other/django/django/contrib/admin/options.py" in wrapper
2.                 return self.admin_site.admin_view(view)(_args, *_kwargs)
   File "/home/kux/workspace/src/other/django/django/utils/decorators.py" in _wrapped_view
3.                     response = view_func(request, _args, *_kwargs)
   File "/home/kux/workspace/src/other/django/django/views/decorators/cache.py" in _wrapped_view_func
4.         response = view_func(request, _args, *_kwargs)
   File "/home/kux/workspace/src/other/django/django/contrib/admin/sites.py" in inner
5.             return view(request, _args, *_kwargs)
   File "/home/kux/workspace/envs/contribute/local/lib/python2.7/site-packages/reversion/revisions.py" in do_revision_context
6.                     return func(_args, *_kwargs)
   File "/home/kux/workspace/src/other/django-cms/cms/admin/pageadmin.py" in change_view
7.         response = super(PageAdmin, self).change_view(request, object_id, extra_context=extra_context)
   File "/home/kux/workspace/src/other/django/django/utils/decorators.py" in _wrapper
8.             return bound_func(_args, *_kwargs)
   File "/home/kux/workspace/src/other/django/django/utils/decorators.py" in _wrapped_view
9.                     response = view_func(request, _args, *_kwargs)
   File "/home/kux/workspace/src/other/django/django/utils/decorators.py" in bound_func
10.                 return func(self, _args2, *_kwargs2)
    File "/home/kux/workspace/src/other/django/django/db/transaction.py" in inner
11.                 return func(_args, *_kwargs)
    File "/home/kux/workspace/src/other/django/django/contrib/admin/options.py" in change_view
12.             if form.is_valid():
    File "/home/kux/workspace/src/other/django/django/forms/forms.py" in is_valid
13.         return self.is_bound and not bool(self.errors)
    File "/home/kux/workspace/src/other/django/django/forms/forms.py" in _get_errors
14.             self.full_clean()
    File "/home/kux/workspace/src/other/django/django/forms/forms.py" in full_clean
15.         self._clean_form()
    File "/home/kux/workspace/src/other/django/django/forms/forms.py" in _clean_form
16.             self.cleaned_data = self.clean()
    File "/home/kux/workspace/src/other/django-cms/cms/admin/forms.py" in clean
17.         cleaned_data = super(PageForm, self).clean()
    File "/home/kux/workspace/src/other/django-cms/cms/admin/forms.py" in clean
18.                 title.slug = self.cleaned_data['slug']

Exception Type: KeyError at /admin/cms/page/6/
Exception Value: 'slug'



Discussion:
Note: If publishing two page with the same slug from the pages tree view, you do get a nice pop up dialog that says:

Page 'master' has the same url '/master/' as current page "master".

Wouldn't it be easier to just not let the user create two pages with the same slug? (look for duplicate slugs at page creation time rather than page publishing time)


Resolving patch:
diff --git a/cms/admin/forms.py b/cms/admin/forms.py
--- a/cms/admin/forms.py
+++ b/cms/admin/forms.py
@@ -92,10 +92,7 @@ def __init__(self, *args, **kwargs):
         
     def clean(self):
         cleaned_data = self.cleaned_data
-        if 'slug' in cleaned_data.keys():
-            slug = cleaned_data['slug']
-        else:
-            slug = ""
+        slug = cleaned_data.get('slug', '')
         
         page = self.instance
         lang = cleaned_data.get('language', None)
@@ -121,17 +118,18 @@ def clean(self):
             #AdminFormsTests.test_clean_overwrite_url validates the form with when no page instance available
             #Looks like just a theoretical corner case
             title = page.get_title_obj(lang)
-            if title:
+            if title and slug:
                 oldslug = title.slug
-                title.slug = self.cleaned_data['slug']
+                title.slug = slug
                 title.save()
                 try:
                     is_valid_url(title.path,page)
                 except ValidationError,e:
                     title.slug = oldslug
                     title.save()
-                    del cleaned_data['published']
-                    self._errors['published'] = ErrorList(e.messages)
+                    if 'slug' in cleaned_data:
+                        del cleaned_data['slug']
+                    self._errors['slug'] = ErrorList(e.messages)
         return cleaned_data
     
     def clean_slug(self):


Test patch: