Search code examples
pythondjangoslug

Best practice: prepopulate SlugField in Django (without Admin module)


In the early days of Django it was possible to prepopulate a SlugField within the Model.

In the Admin module i would use

prepopulated_fields = {'slug':('title',),}

I found a snippet that handles it Unique Slugify but I doubt that it is the best way.

So what would be the best practise to autogenerate a SlugField without using the Admin module?

Id like to use a ModelForm to integrade the form in the frontpage, which should autogenerate a unique slug for the URL.


Solution

  • This is just cut and paste from one of my older (as in less well coded) models. It should show you an idea, with just a little polish, should work.

    from django.template.defaultfilters import slugify
    def get_nickname(self):
        nick = self.name
        vowels = ('a','e','i','o','u')
        first_letter = nick[:1]
        nick = nick[1:]
    
        for vowel in vowels: nick = nick.replace(vowel,'')
        nick = first_letter + nick
        if len(nick) > 8:
            nick = nick[:7]
        return nick
    
    def save(self, force_insert=False, force_update=False, using=None):
        if not self.nickname:
            self.nickname = self.get_nickname() if len(self.name)>8 else self.name
        self.slug = slugify(self.nickname)
        slug_test = SomeModel.objects.filter(slug=self.slug, id=self.id) # corrected to use a generic model name
        if slug_test:
            count = slug_test.count
            self.slug = "{}{}".format(self.slug[:len(self.slug)-1], count)
    
        super(SomeModel, self).save()
    

    UPDATE: tighter code for the get_nick method ...

    >>> name = 'alabama'
    >>> vowels = {'a', 'e', 'i', 'o', 'u'}
    >>> nick = name[0] + ''.join(l for l in name[1:] if l not in vowels)
    >>> nick
    'albm'
    

    FWIW: I just updated my model, eliminating the get_nickname method, and adding a simple lambda to the top of the save method:

    vowels = {'a','e','i','o','u'}
    create_nick = lambda name: name[0] + ''.join(l for l in name[1:] if l not in vowels)[:7]
    if not self.nickname:
        self.nickname = create_nick(self.name) if len(self.name)>8 else self.name
    ...