36👍
So you haven’t posted your code, but assuming your model looks like this:
class Post(models.Model):
title = models.CharField(max_length=100)
slug = models.SlugField(unique=True)
content = models.TextField()
And that you want to pre-fill the slug
from the title, you have a few options depending on where you want to do it:
Post
will be created only by staff users: pre-populate it in the adminPost
will be created outside of the admin: override.save()
method
From the admin
The easiest way to get this in the admin is via the prepopulated_fields
@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
prepopulated_fields = {'slug': ('title',)}
Django will auto-update the slug field as you type the title when creating a post. Very nice UX, but limited to the admin…
Outside of the admin
In the previous example, you might end up with an empty slug if you were to create a post from the console, or from another page. In this case, you can quickly make sure slug is prepopulated by overriding the model’s .save()
method, and calling slugify
in it:
class Post(models.Model):
title = models.CharField(max_length=100)
slug = models.SlugField(unique=True)
content = models.TextField()
def save(self, *args, **kwargs):
self.slug = self.slug or slugify(self.title)
super().save(*args, **kwargs)
Link Post by slug
Disclaimer: if you need more details on this part, I suggest the part 3 of the official tutorial.
Provided you have a URL path:
# urls.py
from django.urls import path
from your_blog import views
urlpatterns = [
path('posts/<slug:the_slug>/', views.post_detail_view, name='show_post'),
]
Then, in your views module you have a view:
# your_blog/views.py
from django.views.generic.detail import DetailView
class PostDetailView(DetailView):
model = Post
# This file should exist somewhere to render your page
template_name = 'your_blog/show_post.html'
# Should match the value after ':' from url <slug:the_slug>
slug_url_kwarg = 'the_slug'
# Should match the name of the slug field on the model
slug_field = 'slug' # DetailView's default value: optional
post_detail_view = PostDetailView.as_view()
You can link to a Post
by calling, in Python:
reverse('show_post', args=[the_post.slug])
Or in a Django template:
<a href="{% url 'show_post' the_post.slug %}">{{ the_post.title }}</a>
EDIT: Post index page
You could then add an index page, generating a list linking to all your posts:
# your_blog/views.py
from django.views.generic import ListView
class PostListView(ListView):
model = Post
# This file should exist somewhere to render your page
template_name = 'your_blog/list_post.html'
And in the view template:
<!-- your_blog/list_post.html -->
<ul>
{% for the_post in object_list %}
<li>
<a href="{% url 'show_post' the_post.slug %}">{{ the_post.title }}</a>
</li>
{% endfor %}
</ul>
Hope that helps 🙂