Search code examples
pythondjangoslug

Django: Problem with Using Slug in Templates


I am a beginner in Django. I am building a Django app, named PhoneReview. It will store reviews related to the latest mobile phone. It will also display phone brands, along with the associated phone models.

I have already created models, views and the template files. Now, I am facing a problem. I can't use slug in URLs. Right now, it looks like this: enter image description here

Here are my codes of models.py located inside PhoneReview folder:

from django.db import models
from django.template.defaultfilters import slugify

# Create your models here.
class Brand(models.Model):
    brand_name = models.CharField(max_length=100)
    origin = models.CharField(max_length=100)
    manufacturing_since = models.CharField(max_length=100, null=True, blank=True)
    slug = models.SlugField(max_length=150, null=True, blank=True)

    def __str__(self):
        return self.brand_name

    def save(self, *args, **kwargs):
        self.slug = slugify(self.brand_name)
        super().save(*args, **kwargs)

class PhoneModel(models.Model):
    brand = models.ForeignKey(Brand, on_delete=models.CASCADE)
    model_name = models.CharField(max_length=100)
    launch_date = models.CharField(max_length=100)
    platform = models.CharField(max_length=100)
    slug = models.SlugField(max_length=150, null=True, blank=True)

    def __str__(self):
        return self.model_name

    def save(self, *args, **kwargs):
        self.slug = slugify(self.model_name)
        super().save(*args, **kwargs)

class Review(models.Model):
    phone_model = models.ManyToManyField(PhoneModel, related_name='reviews')
    review_article = models.TextField()
    date_published = models.DateField(auto_now=True)
    # slug = models.SlugField(max_length=150, null=True, blank=True)
    link = models.TextField(max_length=150, null=True, blank=True)

    def __str__(self):
        return self.review_article

Here are my codes of urls.py located inside PhoneReview folder:

from . import views
from django.urls import path

urlpatterns = [
    path('index', views.BrandListView.as_view(), name='brandlist'),
    path('phonemodel/<int:pk>/', views.ModelView.as_view(), name='modellist'),
    path('details/<int:pk>/', views.ReviewView.as_view(), name='details'),
]

Here are my codes of views.py located inside PhoneReview folder:

from django.views import generic
from .models import Brand, PhoneModel, Review


class BrandListView(generic.ListView):
    template_name = 'PhoneReview/index.html'
    context_object_name = 'all_brands'

    def get_queryset(self):
        return Brand.objects.all()


class ModelView(generic.DetailView):
    model = PhoneModel
    template_name = 'PhoneReview/phonemodel.html'

class ReviewView(generic.DetailView):
    model = Review
    template_name = 'PhoneReview/details.html'

Here are my codes of apps.py located inside PhoneReview folder:

from django.apps import AppConfig


class PhonereviewConfig(AppConfig):
    name = 'PhoneReview'

Here are my codes of index.html located inside templates folder:

{% extends 'PhoneReview/base.html' %}

{% load static %}

{% block title%}
Brand List
{% endblock %}

{% block content %}
<!--Page content-->
<h1>This is Brand List Page</h1>
<h2>Here is the list of the brands</h2>
    <ul>
        {% for brand in all_brands %}
<!--            <li>{{ brand.brand_name }}</li>-->
            <li><a href = "{% url 'modellist' brand.id %}">{{ brand.brand_name }}</a></li>

        {% endfor %}
    </ul>
<img src="{% static "images/brandlist.jpg" %}" alt="Super Mario Odyssey" /> <!-- New line -->
{% endblock %}

Here are my codes of phonemodel.html located inside templates folder:

{% extends 'PhoneReview/base.html' %}

{% load static %}

{% block title%}
Phone Model Page
{% endblock %}

{% block content %}
<!--Page content-->
<h1>This is Phone Model Page</h1>
<h2>Here is the phone model</h2>
    <ul>
        <li><a href = "{% url 'details' phonemodel.id %}">{{ phonemodel.model_name }}</a></li>
    </ul>
<img src="{% static "images/brandlist.jpg" %}" alt="Super Mario Odyssey" /> <!-- New line -->
{% endblock %}

In index.html, I tried to replace <li><a href = "{% url 'details' phonemodel.id %}">{{ phonemodel.model_name }}</a></li> with <li><a href = "{% url 'details' phonemodel.slug %}">{{ phonemodel.model_name }}</a></li>. But I get error.

How can I fix the issue?

Update: I added the codes provided by @arjun. However, I am getting an error. It says the following

OperationalError at /index
no such table: PhoneReview_brand

Solution

  • You need to pass slug instead of pk through your url if you want to use slug

    path('phonemodel/<slug:slug>/', views.ModelView.as_view(), name='modellist'),
    path('details/<slug:slug>/', views.ReviewView.as_view(), name='details'),
    

    Now in template instead of id

    <li><a href = "{% url 'details' phonemodel.slug %}">{{ phonemodel.model_name }}</a></li>
    

    And it's better to have unique slug field

     slug = models.SlugField(max_length=150, unique=True)
    

    Also I will suggest you to use the django-autoslug. It is a reusable Django library that provides an improved slug field which can automatically populate itself from another field.

    EDIT:You haven't passed context_object_name in your detail view so provide the context here

    class ModelView(generic.DetailView):
        model = PhoneModel
        template_name = 'PhoneReview/phonemodel.html'
        context_object_name= 'phonemodel'