Search code examples
djangourlslug

Slugfield not working if field name is different from slug


Good evening, Django is completely new for me and it's my first question here. I'm trying to create a Webapp. I'm using Django, Python and MariaDB. I created a project with two apps and I have a model for each app. In the fist one I used "slug" as field name and everything is working fine. In the second one I wanted to differentiate that field giving a different name (bk_slug) defined as SlugField. I tried to use the same kind of instructions lines and modifying them for the field name it seems not working. I cannot have the right URL (Class based ListView) and cannot access to the Class based DetailView.... Thanks in advance for your support.

models.py


    from django.db import models
    from django.conf import settings
    from django.utils import timezone
    from django.urls import reverse
    
    # book masterdata
    
    
    class Book(models.Model):
        bk_title = models.CharField("Book Title", max_length=100, 
            primary_key=True)
        bk_originaltitle = models.CharField("Book original Title", 
            max_length=100, blank=True)
        bk_author = models.CharField("Author", max_length=50)
        bk_editor = models.CharField("Editor", max_length=50)
        bk_editiondate = models.CharField("Book Edition date", 
            max_length=30)
        bk_recblocked = models.BooleanField("Book record blocked")
        bk_creator = models.ForeignKey(
            settings.AUTH_USER_MODEL, on_delete=models.PROTECT, 
            related_name='+', verbose_name="Created by")
        bk_creationdate = models.DateTimeField("Creation date", 
            auto_now=True)
        bk_modifier = models.ForeignKey(settings.AUTH_USER_MODEL, 
            on_delete=models.PROTECT,                                    
            related_name='+', verbose_name="Last modification by")
        bk_modified = models.DateTimeField("Last modification date", 
            auto_now=True)
        bk_slug = models.SlugField(max_length=100, allow_unicode=True, 
            blank=True)
    
        def __str__(self):
            return self.bk_title
    
        def get_absolute_url(self):
            return reverse('book_detail', kwargs={'slug': self.bk_slug})

urls.py

    from django.urls import path
    
    from dimlibrary.views import BookListView
    from dimlibrary.views import BookDetailView
    
    urlpatterns = [
        path('', BookListView.as_view(), name='book_list'),
        path('<slug:bk_slug>/', BookDetailView.as_view(), 
            name='book_detail'),
    ]

views.py

    from django.shortcuts import render
    
    # Create your views here.
    from django.shortcuts import render
    from django.utils import timezone
    from django.views.generic.list import ListView
    from django.views.generic.detail import DetailView
    
    from dimlibrary.models import Book
    
    # book views :
    # List view
    class BookListView(ListView):
    
        model = Book
    
        def get_context_data(self, **kwargs):
            context = super().get_context_data(**kwargs)
            return context 
            
    
    # Details View
    class BookDetailView(DetailView):
    
        model = Book
    
        def get_context_data(self, **kwargs):
            context = super().get_context_data(**kwargs)
            return context

```html

    {% extends 'base/base.html' %}
    {% load static %}
    {% block content %}
    
    <h1>Books List</h1>
    <ul>
        {% for book in object_list %}
            <li><a href="{{ dimlibrary.book.get_absolute_url }}">{{ 
                          book.bk_title }}</a> - {{ book.bk_author }} - 
                  {{ book.bk_editor }}</li>
        {% empty %}
            <li>No book registred yet.</li>
        {% endfor %}
        </ul>
    
    
    {% endblock content %} 


Solution

  • In your DetailView, you need to specify the slug_field [Django-doc] as 'bk_slug':

    class BookDetailView(DetailView):
        model = Book
        slug_field = 'bk_slug'
        
        def get_context_data(self, **kwargs):
            context = super().get_context_data(**kwargs)
            return context

    In the model, you will need to slugify(…) [Django-doc] the name, so:

    from django.utils.text import slugify
    
    class Book(models.Model):
        # …
    
        def save(self, *args, **kwargs):
            if not self.bk_slug:
                self.bk_slug = slugify(self.title)
            return super().save(*args, **kwargs)