James
James

Reputation: 25

Django post primary key as slug? How do I reference the primary key in models.py?

When creating the slug for my post model, I want to use the object's primary key as the slug. However when I create a new post, instance.id is NoneType and not an integer like I'd imagine.

Here is my model:

class Post(models.Model):
    id = models.AutoField(primary_key=True)
    title = models.CharField(max_length=50, null=False, blank=False)
    body = models.TextField(max_length=5000, null=False, blank=False)
    image = models.ImageField(upload_to=upload_location, null=False, blank=False)
    date_published = models.DateTimeField(auto_now_add=True, verbose_name="date published")
    date_updated = models.DateTimeField(auto_now=True, verbose_name="date updated")
    author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    slug = models.SlugField(blank=True, unique=True)

    def __str__(self):
        return self.title
    
@receiver(post_delete, sender=Post)
def submission_delete(sender, instance, **kwargs):
    instance.image.delete(False)

def pre_save_blog_post_receiver(sender, instance, *args, **kwargs):
    if not instance.slug:
        instance.slug = slugify(instance.id)

pre_save.connect(pre_save_blog_post_receiver, sender=Post)

As you can see in pre_save_blog_post_receiver, instance.id returns as None. How do I correctly reference the primary key in this situation?

Upvotes: 1

Views: 1012

Answers (1)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 476574

You need to use post_save in case you create a Post object, since before it is committed to the database, there is no primary key. The database "distributes" primary keys.

Slugifying with an id is however a bit "odd". The idea of a slug is to make a visually pleasant variant of the title or some other text-related attribute.

It might also be more convenient to make use of a AutoSlugField [readthedocs.io] of the django-autoslug [readthedocs.io] package:

from autoslug import AutoSlugField

class Post(models.Model):
    id = models.AutoField(primary_key=True)
    title = models.CharField(max_length=50)
    body = models.TextField(max_length=5000)
    image = models.ImageField(upload_to=upload_location)
    date_published = models.DateTimeField(auto_now_add=True, verbose_name='date published')
    date_updated = models.DateTimeField(auto_now=True, verbose_name='date updated')
    author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    slug = models.SlugField(populate_from='title')

    def __str__(self):
        return self.title

Upvotes: 2

Related Questions