Search code examples
djangosaveadminslug

Can't edit slug field in Django Admin


I have a Django app with a model that has a slug field. Up until now, I have been simply slugifying the model's label field, and making the slug read only in the admin. My client now wants me to allow them to be able to edit the slug themselves to whatever they want. I took off the readonly access in the admin, and changed the save method on my model to not use its slugified label. When I go to the admin however, and try to change the slug, it doesn't change when I save it. When I try to add a new model instance, even when I enter in something, it empties out the form field, and says that the slug field is required. I read in the Django documentation that it is custom to pre-populate the slug field, but it didn't say anywhere that it was required.

Model

class WebPage(models.Model):
    template = models.CharField(max_length=50, blank=True, null=True, choices=TEMPLATE_CHOICES, default='default')

    label = models.CharField(max_length=100)
    slug = models.SlugField(unique=True)

    meta_title = models.CharField(max_length=100, blank=True, null=True,
                                  help_text='This shows at the top of the browser, usually in the tab.')
    meta_description = models.CharField(max_length=180, blank=True, null=True,
                                        help_text='Optimal length is roughly 155 characters')
    meta_tags = models.CharField(max_length=500, blank=True, null=True)

    billboards = models.ManyToManyField(Billboard, blank=True, null=True)

    image_cover = FileBrowseField(max_length=400, blank=True, null=True, help_text='Roughly 1400px by 400px',
                                  verbose_name='Cover image')
    header_content = models.TextField(blank=True, null=True)

    # template overrides
    image_desktop = FileBrowseField(max_length=400, blank=True, null=True,
                                    verbose_name='Desktop logo', help_text='Transparent .png')
    image_mobile = FileBrowseField(max_length=400, blank=True, null=True,
                                   verbose_name='Mobile logo', help_text='Transparent .png')
    nav_color = models.CharField(max_length=7, blank=True, null=True)
    nav_hover_color = models.CharField(max_length=7, blank=True, null=True)
    pre_nav_color = models.CharField(max_length=7, blank=True, null=True)
    page_header_color = models.CharField(max_length=7, blank=True, null=True)

    is_published = models.BooleanField(default=True)
    create_date = models.DateTimeField(auto_now_add=True)
    modified_date = models.DateTimeField(auto_now=True)

    def __unicode__(self):
        return self.label

    def save(self, *args, **kwargs):
        self.slug = slugify(self.slug)

        super(WebPage, self).save(*args, **kwargs)

Admin

class WebPageAdmin(admin.ModelAdmin):
    model = WebPage
    list_display = ('label', 'slug', 'is_published', 'create_date')
    list_filter = ('modified_date', 'is_published')
    list_editable = ('is_published',)

    search_fields = ('label',)
    save_as = True

    # readonly_fields = ('slug',)
    filter_horizontal = ('billboards',)

    inlines = [
        PageSectionInline,
    ]

    fieldsets = (

        (None, {
            'classes': ('suit-tab suit-tab-general full-width',),
            'fields': ('template', 'label', 'slug', 'billboards', 'is_published')
        }),

        (None, {
            'classes': ('suit-tab suit-tab-overrides full-width',),
            'fields': ('image_desktop', 'image_mobile', 'nav_color', 'nav_hover_color', 'pre_nav_color',
                       'page_header_color')
        }),

        (None, {
            'classes': ('suit-tab suit-tab-seo full-width',),
            'fields': ('meta_title', 'meta_description', 'meta_tags', 'slug')
        }),

    )

    suit_form_tabs = (('general', 'General'), ('sections', 'Sections'),
                      ('overrides', 'Template Overrides'), ('seo', 'SEO'))

    class Media:
        js = [
            '//cdn.tinymce.com/4/tinymce.min.js',
            '/static/admin_js/tinymce_init.js',
            '/static/page/admin/webpage.js'
        ]

Solution

  • You're always using the existing slug field in the save function, check for a change in the value.

    def save(self, *args, **kwargs):
        self.slug = slugify(kwargs.pop('slug', self.slug))
    
        super(WebPage, self).save(*args, **kwargs)