0

I'm trying to integrate a custom method on a Django model

class Post(models.Model):
    author = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, blank=True)
    title = models.CharField(max_length=200)
    text = MarkdownField()
    slug = models.SlugField(unique=True, blank=True)
    created = models.DateTimeField(auto_now_add=True)
    published_date = models.DateTimeField(blank=True, null=True)

    def generate_unique_slug(self):
        slug = self._meta.get_field('slug')
        max_length = slug.max_length
        slug = orig = slugify(self.title)[:max_length]

        for x in itertools.count(1):
            if not Post.objects.filter(slug=slug).exists():
                break

            # Truncate the original slug dynamically. Minus 1 for the hyphen.
            slug = "%s-%d" % (orig[:max_length - len(str(x)) - 1], x)

    def publish(self):
        self.published_date = timezone.now()
        self.generate_unique_slug()
        self.save()

When called from "publish", "generate_unique_slug" doesn't work. For example, I'll do this from terminal

>>> p = Post(title="Title Example", text="Text example")
>>> p.publish()
>>> p.title
'Title Example'
>>> p.published_date
datetime.datetime(2016, 6, 18, 14, 45, 12, 710452, tzinfo=<UTC>)
>>> p.slug
u''

I've also tried this

>>> p.generate_unique_slug()
>>> p.slug
u''

What am I doing wrong?

3 Answers 3

1

You're not updating the slug of your model. Add self.slug = slug at the end of generate_unique_slug:

def generate_unique_slug(self):
    # your code
    self.slug = slug
Sign up to request clarification or add additional context in comments.

4 Comments

That's it, thanks! Anyway, when I create the Post from the admin panel, the slug isn't created: any thoughts on how I might get that?
The slug is generated only when you run the publish function. Is this where your problem is? If so, you probably want to override the save method.
Because the method will not be called when creating a new Post. You can modify the save method of your model to always call generate_unique_slug. See this
Thank you. I made it by overriding the save method, and putting "super(Post, self).save()" at the end.
0

generate_unique_slug neither change any instance attribute nor return anything.

You should change slug in slug = "%s-%d" % (orig[:max_length - len(str(x)) - 1], x) to self.slug = ....

Comments

0

This answer does not fix your code, but I think it is a good option as it covers multiple cases.

There is a library called uuslug designed to do exactly this. It might be worth checking out.

A example from the repository:

from django.db import models
from uuslug import uuslug

# Override your object's save method with something like this (models.py)
class CoolSlug(models.Model):
    name = models.CharField(max_length=100)
    slug = models.CharField(max_length=200)

    def __unicode__(self):
        return self.name

    def save(self, *args, **kwargs):
        self.slug = uuslug(self.name, instance=self)
        super(CoolSlug, self).save(*args, **kwargs)

name = "john"
c = CoolSlug.objects.create(name=name)
c.save()
print(c.slug) # => "john"

c1 = CoolSlug.objects.create(name=name)
c1.save()
print(c1.slug) # => "john-1"

I also believe you can change slug = models.CharField(max_length=200) to slug = models.SlugField(max_length=200), and it would still work properly.

Edit after comment:

Instead of overriding save, you could do the following:

from uuslug import slugify

class Post(models.Model):
    author = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, blank=True)
    title = models.CharField(max_length=200)
    text = MarkdownField()
    slug = models.SlugField(unique=True, blank=True)
    created = models.DateTimeField(auto_now_add=True)
    published_date = models.DateTimeField(blank=True, null=True)


    def publish(self):
        self.published_date = timezone.now()
        self.slug = slugify(self.title, max_length=self._meta.get_field('slug'))
        self.save()

Does this fix the problem?

1 Comment

Thanks for the library, anyway I think you misread the line, as the slug line is "slug = models.SlugField(unique=True, blank=True)" :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.