13

I have tried searching for this question, but mostly I saw regex patterns, so:

  1. How can I fill my blog model slug field automatically with the post name without filling it out myself

  2. How can I make a link to go to a single post page using the slug WITHOUT regex

Chris
  • 1,206
  • 2
  • 15
  • 35
Cole
  • 564
  • 1
  • 4
  • 14
  • This tutorial is best - https://studygyaan.com/django/how-to-create-a-unique-slug-in-django – Cipher Apr 16 '20 at 17:43

1 Answers1

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:

  1. Post will be created only by staff users: pre-populate it in the admin
  2. Post 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 :)

Bruno A.
  • 1,765
  • 16
  • 17
  • Your lasr line that says 'the_post.title' and the_post.slug, I thought it should have been Post.title and Post.slug, as the model name is Post and not the_post. Or am I wrong? Plus this is a lot to take in. Thanks a lot for taking your time out for this. – Cole Oct 30 '18 at 18:18
  • The model is Post, and the_post is an instance of Post. You would get an instance by fetching it: the_post = Post.objects.get(id=1). You could have all your posts in Post.objects.all() and the last line in a template loop. See the making queries section of the docs https://docs.djangoproject.com/en/2.1/topics/db/queries/ – Bruno A. Oct 30 '18 at 23:01
  • Went through this again with the edit!! Thanks. Got it all now. Would be more grateful if you could explain here where to serve static files from? As my instructor in my tut video said its "unprofessional" to serve static files with Django. – Cole Oct 31 '18 at 14:52
  • Thank you @bruno-a :) If I use {% url 'show_post', the_post.slug %} its shown me a Template syntax error. But if you remove ",", then you have this {% url 'show_post' the_post.slug %}, all works fine – MaxDragonheart Nov 17 '18 at 12:23