losee
losee

Reputation: 2238

How do I make the slugs work in django

I have followed the basic polls tutorial and I have tried to modify it to make it work for slugs but it's not working. I went from this in my views.py

def detail(request, article_id):
    details = "blog/detail.html"
    context = {
        "article": get_object_or_404(Article, pk=article_id)
    }
    return render(request, details, context)

and

url(r'^(?P<article_id>[0-9]+)/$', views.detail, name='detail'),

to this in my views.py

def detail(request, slug):
    details = "blog/detail.html"
    context = {
        "article": get_object_or_404(Article, slug)
    }
    return render(request, details, context)

and

url(r'^(?P<slug>[\w-]+)/$', views.detail, name='detail'),

this is my models.py

from django.db import models

from django.contrib.auth.models import User



class Article(models.Model):
    author = models.ForeignKey(User)
    title = models.CharField(max_length=250)
    slug = models.SlugField()
    body = models.TextField()
    created = models.DateTimeField(auto_now=True)

    def __str__(self):
        return self.title

this is my admin.py

from django.contrib import admin

from .models import Article


@admin.register(Article)
class ArticleAdmin(admin.ModelAdmin):
    prepopulated_fields = {"slug": ("title",)}

but it's not working. How Do I get the slugs to show in my url

Upvotes: 4

Views: 7269

Answers (2)

Saturnix
Saturnix

Reputation: 10564

You're missing the parameter name in get_object_or_404. Assuming that your Article model has a SlugField named slug:

get_object_or_404(Article, slug=slug)

EDIT: User update the question providing the model. This part is no longer needed.

Since you didn't posted your Article model, I'm gonna provide an example of how you should code it to make it compatible with my example:

from django.utils.text import slugify
from django.db import models

class Article(models.model):
    #…
    slug = models.SlugField(unique=True)

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

Copied from this answer. Notice how we override the save method to automatically generate the slug. Might not be a good idea depending on your architecture. I'd recommend to call slugify in a view or in a modelform like in this tutorial.

Upvotes: 1

Rahul Gupta
Rahul Gupta

Reputation: 47856

In your views, you need to pass slug argument.

def detail(request, slug):
    details = "blog/detail.html"
    context = {
        "article": get_object_or_404(Article, slug=slug) # pass slug 
    }
    return render(request, details, context)

If you are creating Articles using admin, then the slug will get prepopulated using title field. But, if you want to create an article other than doing it in admin, you need to call slugify() function explicitly in your model's save() and assign it to the article object before saving it.

You can do something like:

class Article(models.Model):

    def save(self, *args, **kwargs):
        self.slug = slugify(self.title) # set the slug explicitly
        super(Article, self).save(*args, **kwargs) # call Django's save()

Note: Since you are using slug instead of id for detail view, this means that no 2 articles should have the same slug i.e. the same title. Add unique=True constraint in your model for handling this.

Upvotes: 5

Related Questions