1

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

Krzysztof Madej
  • 32,704
  • 10
  • 78
  • 107
Firefinch
  • 29
  • 6

3 Answers3

1

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

blondelg
  • 916
  • 1
  • 8
  • 25
  • this doesnt seem to work. The url pattern now looks like http://127.0.0.1:8000/blog/2 and i get the error Page not found (404). What could be wrong? – Firefinch Jul 23 '20 at 22:48
  • the whole error is Page not found (404) Request Method: GET Request URL: http://127.0.0.1:8000/blog/2 Raised by: blog.views.EntryView No entry found matching the query – Firefinch Jul 23 '20 at 22:50
0

If you are using a Class Based View you should use a slug. First add a new field entry_slug to your Entry model and override the save method in order to automatically generate the entry_slug field:

class Entry(models.Model):
    entry_title = models.CharField(max_length=50)
    entry_slug = models.CharField(max_length=50)
    ...

    def save(self, *args, **kwargs):
            self.entry_slug = slugify(self.entry_title )
            super(Entry, self).save(*args, **kwargs) 

You can do by replacing the pk with entry_slug:

path('entry/<slug:entry_slug>/', EntryView.as_view(), name="entry-detail")
Aurélien
  • 1,617
  • 1
  • 21
  • 33
  • when i do this, i get this error: Generic detail view EntryView must be called with either an object pk or a slug in the URLconf. – Firefinch Jul 23 '20 at 21:51
0

Currently you are passing an integer through your url. All you need to do is modify this slightly to pass a string through the url. Here is a similar question that discusses how to accomplish this.

As for changes you need to make in your code, urls.py will need to be updated

path('entry/<str:title>/', EntryView.as_view(), name="entry-detail")

You haven't provided your blog post view, but it will then look something like this:

def post(request, title):
    template = "template.html"
    post = Posts.objects.filter(entry_title==title)
    return render(request, template, {'post':post})

SevvyP
  • 375
  • 1
  • 7
  • i am using the class based approach. I've edited my question to show what the class looks like. How do i proceed? – Firefinch Jul 23 '20 at 21:59