Repository: stephenmcd/mezzanine

Issue:
Automatically updating children page's slug to reflect parent title change
Hi everyone, I have an issue that I asked about on the mezzanine google group:

https://groups.google.com/forum/#!topic/mezzanine-users/9FRTeTut3oo

Steps to recreate the issue:
1. Create new page at the top level (this is the parent page).
2. Create a child page to that parent page.
3. Check that both links are working (they are).
4. Change title of the parent page, delete the url to leave it blank so it autogenerates to match the new title.
5. The child page url is not updated and thus is a broken link now.

Basically I was wondering if there's a solution for updating the slugs of all of a page's children if that page's title and slug are updated. Currently it does not.



Discussion:

Resolving patch:
diff --git a/mezzanine/core/models.py b/mezzanine/core/models.py
--- a/mezzanine/core/models.py
+++ b/mezzanine/core/models.py
@@ -71,16 +71,22 @@ def __str__(self):
 
     def save(self, *args, **kwargs):
         """
-        Create a unique slug by appending an index.
+        If no slug is provided, generates one before saving.
         """
         if not self.slug:
-            self.slug = self.get_slug()
+            self.slug = self.generate_unique_slug()
+        super(Slugged, self).save(*args, **kwargs)
+
+    def generate_unique_slug(self):
+        """
+        Create a unique slug by passing the result of get_slug() to
+        utils.urls.unique_slug, which appends an index if necessary.
+        """
         # For custom content types, use the ``Page`` instance for
         # slug lookup.
         concrete_model = base_concrete_model(Slugged, self)
         slug_qs = concrete_model.objects.exclude(id=self.id)
-        self.slug = unique_slug(slug_qs, "slug", self.slug)
-        super(Slugged, self).save(*args, **kwargs)
+        return unique_slug(slug_qs, "slug", self.get_slug())
 
     def get_slug(self):
         """
diff --git a/mezzanine/pages/admin.py b/mezzanine/pages/admin.py
--- a/mezzanine/pages/admin.py
+++ b/mezzanine/pages/admin.py
@@ -22,12 +22,10 @@ class PageAdminForm(DisplayableAdminForm):
 
     def clean_slug(self):
         """
-        If the slug has been changed, save the old one. We will use it later
-        in PageAdmin.model_save() to make the slug change propagate down the
-        page tree.
+        Save the old slug to be used later in PageAdmin.model_save()
+        to make the slug change propagate down the page tree.
         """
-        if self.instance.slug != self.cleaned_data['slug']:
-            self.instance._old_slug = self.instance.slug
+        self.instance._old_slug = self.instance.slug
         return self.cleaned_data['slug']
 
 
@@ -140,12 +138,12 @@ def changelist_view(self, request, extra_context=None):
 
     def save_model(self, request, obj, form, change):
         """
-        Set the ID of the parent page if passed in via querystring, and make
-        sure the new slug propagates to all descendant pages.
+        Set the ID of the parent page if passed in via querystring, and
+        make sure the new slug propagates to all descendant pages.
         """
-        if change and hasattr(obj, "_old_slug"):
+        if change and obj._old_slug != obj.slug:
             # _old_slug was set in PageAdminForm.clean_slug().
-            new_slug = obj.slug
+            new_slug = obj.slug or obj.generate_unique_slug()
             obj.slug = obj._old_slug
             obj.set_slug(new_slug)
 


Test patch: