pythondjangodjango-urlsurl-pattern

django custom blog post urls


I am learning django by building a simple blogging app. While its all but done, I currently have individual posts having a url in the format https://my_site_dot_com/blog/entry/38/ where the number 38 corresponds to the primary key of said post. What i want is it to have the format https://my_site_dot_com/blog/entry/this_is_custom_title/ where "this_is_custom_title" corresponds to the heading of the post. I have no idea how to accomplish this. Can anyone offer any assistance? My model looks like:

class Entry(models.Model):
    entry_title = models.CharField(max_length=50)
    entry_text = models.TextField()
    image = models.FileField(upload_to="media", blank=True)
    entry_date = models.DateTimeField(auto_now_add=True)
    entry_author = models.ForeignKey(User, on_delete=models.CASCADE)

        class Meta:
            verbose_name_plural = "blog"
    
        def __str__(self):
            return self.entry_title

I want the entry_title to the the custom url instead of the primary key.

My urls.py looks like this:

urlpatterns = [
    path('', HomeView.as_view(), name="blog-home"),
    path('entry/<int:pk>/', EntryView.as_view(), name="entry-detail"),
    path('create_entry/', CreateEntryView.as_view(success_url='/'), name='create_entry'),
]

Edit: The class handing the post looks like this:

class EntryView(DetailView):
    model = Entry
    template_name = 'blog/entry_detail.html'
    data_set = random_info()
    stuff_for_post = {
        "info": data_set
    }

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['rand_im'] = random_image()
        context['tags'] = ['tag1','tag2','tag3']

        return context

I'm an absolute noob in django and come from android/java. So please give an easy to understand explanation. Thanks in advance


Solution

  • You may add a slug field to your Entry model and a get_absolute_url method. Don't forget to import reverse function from Django's url module.

    from django.urls import reverse
    
    class Entry(models.Model):
        entry_title = models.CharField(max_length=50)
        entry_text = models.TextField()
        image = models.FileField(upload_to="media", blank=True)
        entry_date = models.DateTimeField(auto_now_add=True)
        entry_author = models.ForeignKey(User, on_delete=models.CASCADE)
        slug = models.SlugField()
    
        def get_absolute_url(self):
            return reverse('entry_detail', kwargs={'slug': self.slug})
    
        class Meta:
            verbose_name_plural = "blog"
    
        def __str__(self):
            return self.entry_title
    

    Then, within the urls.py module of your app, add the following url pattern to the urlpatterns list. Don't forget to load the corresponding view, I guess it may be EntryView in this case.

    from django.urls import path
    from .views import EntryView
    
    urlpatterns = [
        ...
        path('<slug:slug>', EntryView.as_view(), name='entry_detail'), # new
        ...
    ]
    

    Then the slug should replace the primary key pattern in the url.

    To go a bit further, you can use a method within your model that slugify your title for instance. (define the method within the model then call it from the save method of the model, by overriding the save method)

    https://docs.djangoproject.com/en/3.0/ref/utils/#django.utils.text.slugify