I want my URL's to show slug instead of id. After following a Youtube video I reached to a stage where admin is automatically creating slugs when I save my products. But still I can not figure out how to show slug in url of detailsview.
I created a utils.py in my project folder which is named as myawesomecart
import string
import random
from django.utils.text import slugify
def random_string_generator(size=10, chars=string.ascii_lowercase + string.digits):
return ''.join(random.choice(chars) for _ in range(size))
def unique_slug_generator(instance, new_slug=None):
"""
This is for a Django project and it assumes your instance
has a model with a slug field and a title character (char) field.
"""
if new_slug is not None:
slug = new_slug
else:
slug = slugify(instance.title)
Klass = instance.__class__
qs_exists = Klass.objects.filter(slug=slug).exists()
if qs_exists:
new_slug = "{slug}-{randstr}".format(
slug=slug,
randstr=random_string_generator(size=4)
)
return unique_slug_generator(instance, new_slug=new_slug)
return slug
my models.py file is as under
from django.db import models
from django.db.models.signals import pre_save #2 slug
from myawesomecart.utils import unique_slug_generator
# Create your models here.
class product(models.Model):
title = models.CharField(max_length=50)
slug= models.SlugField(max_length = 250, null = True, blank = True)
category = models.CharField(max_length=50, default="your category here")
subcategory = models.CharField(max_length=50, default= "your subcategory here")
price = models.IntegerField(null=True)
desc = models.CharField(max_length=500)
pub_date = models.DateField()
image = models.ImageField(upload_to="shop/images" , null= True)
def __str__(self):
return self.title
def slug_generator(sender,instance,*args, **kwargs): #1 slug
instance.slug = unique_slug_generator(instance)
pre_save.connect(slug_generator,sender = product) #3 slug
urls.py file of my app named shop
from django.urls import path
from . import views
from . views import product_list_view, product_detail_view
urlpatterns = [
path('',views.index,name='shophome'),
path('about/',views.about,name='About us'),
path('contact/',views.contact,name='contact'),
path('tracker/',views.tracker,name='trackingstatus'),
path('search/',views.search,name='search'),
path('productview/',views.productview,name='productview'),
path('checkout/',views.checkout,name='checkout'),
path('list/',views.product_list_view,name='list'),
path('checkout/',views.checkout,name='checkout'),
path('<id>/',product_detail_view),
]
views.py file of my app
from django.shortcuts import render,get_object_or_404 #get obj is for detailed view
from django.views.generic import ListView, DetailView
from . models import product
# Create your views here. b8
def index(request):
return render(request,'shop/index.html')
def about(request):
return render(request,'shop/index.html')
def contact(request):
return render(request,'shop/index.html')
def tracker(request):
return render(request,'shop/index.html')
def search(request):
return render(request,'shop/index.html')
def productview(request):
return render(request,'shop/index.html')
def checkout(request):
return render(request,'shop/index.html')
def product_list_view(request):
allproducts= product.objects.all() #allproduct is a variable ,kuch bhi likh lo yaha,aage jo product likha hai ye model hai apna
context= {'allproducts': allproducts} #variable pass hua hai bas
return render(request, 'shop/listview.html', context)
def product_detail_view(request, id=None):
allproducts= product.objects.get(id=id) #product.objects.all karne par 404 error milega
context= {'allproducts': allproducts}
return render(request, 'shop/detailview.html', context)
'''
#DETAILED VIEW
#detailedview baane ke bad listview ke html me change karna hoga
<h1>List of products</h1>
{% for product in allproducts %}
<!--#{{ product.product_name }} -->
<a href="/shop/{{product.id }}">{{ product.product_name }} </a> #this is the change
<br><br>
{% endfor %}
</table>
'''
detailview.html file of my app
<html>
<head>
<meta charset="UTF-8">
<title>Movies</title>
</head>
<body>
<h1><img src='{{ allproducts.image.url }}' class='img-fluid' /> </h1>
<p> {{ allproducts.title}}</p>
<p>{{ allproducts.category }}</p>
<p> {{ allproducts.price }}</p>
<p>Go back to the <a href="/shop/list/">list of products </a></p>
</body>
<script>'undefined'=== typeof _trfq || (window._trfq = []);'undefined'=== typeof _trfd && (window._trfd=[]),_trfd.push({'tccl.baseHost':'secureserver.net'}),_trfd.push({'ap':'cpsh'},{'server':'p3plcpnl0769'}) // Monitoring performance to make your website faster. If you want to opt-out, please contact web hosting support.</script><script src='https://img1.wsimg.com/tcc/tcc_l.combined.1.0.6.min.js'></script></html>
listview.html file of app
<html>
<head>
<meta charset="UTF-8">
<title>products</title>
</head>
<body>
<h1>List of products</h1>
{% for product in allproducts %}
<!--#{{ product.product_name }} -->
<a href="/shop/{{product.id }}">{{ product.title }} </a>
<br><br>
{% endfor %}
</table>
</body>
<script>'undefined'=== typeof _trfq || (window._trfq = []);'undefined'=== typeof _trfd && (window._trfd=[]),_trfd.push({'tccl.baseHost':'secureserver.net'}),_trfd.push({'ap':'cpsh'},{'server':'p3plcpnl0769'}) // Monitoring performance to make your website faster. If you want to opt-out, please contact web hosting support.</script><script src='https://img1.wsimg.com/tcc/tcc_l.combined.1.0.6.min.js'></script></html>
You have to use the slug
instead of the id
in your url pattern:
path('<slug>/',product_detail_view),
Then you have to update your view to handle a slug instead of an id
def product_detail_view(request, slug=None):
allproducts= product.objects.get(slug=slug) #product.objects.all karne par 404 error milega
context= {'allproducts': allproducts}
return render(request, 'shop/detailview.html', context)
You also need to update your listview template in order to build links with slugs
<a href="/shop/{{product.slug }}">{{ product.title }} </a>