I want my slugs to show up in my URLS instead of the number ID of the image that is being viewed. I can't seem to get it working. Can anyone spot what I'm missing/doing wrong? TYIA
models.py:
class PostImage(models.Model):
image = models.ImageField(null=False, blank=False, upload_to="images", default="default.png")
image_title = models.CharField(max_length=100, null=False, blank=False, default="")
slug = models.SlugField(null=True)
def save(self, *args, **kwargs):
self.slug = self.slug or slugify(self.title)
super().save(*args, **kwargs)
def __str__(self):
return self.image_title
class Meta:
verbose_name_plural = 'PostImage'
views.py:
def galleryPage(request):
images = PostImage.objects.all()
context = {'images':images}
return render(request, 'gallery.html', context)
def viewImage(request, slug):
photo = PostImage.objects.get(id=slug)
return render(request, 'viewimage.html', {'photo': photo, 'slug': slug})
urls.py:
path('viewimage/<slug:slug>/', views.viewImage, name='viewimage'),
admin.py:
@admin.register(PostImage)
class PostAdmin(admin.ModelAdmin):
prepopulated_fields = {'slug': ('image_title',)}
These are the html pages, the first is where the image is clicked, the second is where the image is shown and also where I would want the slug showing in the URL on browser rather than the id/number.
html for page that image is selected:
</head>
<body>
<header>{% include 'navbardesktop.html' %}</header>
<div >
<div id="gallerygrid1">
<div >
{% for photo in images %}
<div id="gallerygrid2">
<a href="{% url 'viewimage' photo.id %}"
><img
src="{{photo.image.url}}"
style=""
/></a>
</div>
{% empty %}
<h3>No Projects...</h3>
{% endfor %}
</div>
</div>
</div>
</body>
</html>
html for page where image is shown:
</head>
<body>
<header>{% include 'navbardesktop.html' %}</header>
<div >
<div >
<a href="{% url 'gallery' %}"
><img src="{{photo.image.url}}"
/></a>
<h2 >{{photo.image_title}}</h2>
<p >
Interested in purchasing this as a print? Contact me for more
information regarding price and sizes.
</p>
<a href="{% url 'contact' %}" type="button"
>Contact</a
>
<a href="{% url 'gallery' %}" type="button"
>Gallery</a
>
</div>
</div>
</body>
</html>
CodePudding user response:
Short answer
The url that is opening the page with the image is <a href="{% url 'viewimage' photo.id %}">
, and since you are feeding in photo.id
, that's what you're getting. You could change it to <a href="{% url 'viewimage' photo.slug %}">
and that should solve the problem.
But
But this will create problems since you are allowing null=True
for the slug
field, so what happens when you have a PostImage
instance with no slug
? An error, since your url is expecting a parameter, <slug:slug>
:
path('viewimage/<slug:slug>/', views.viewImage, name='viewimage'),
I don't see why you need to make the slug field null, since you have a save() function that will fill it in automatically, though it does have a typo, I believe, and that is slugify(self.title)
. What is self.title
? Perhaps you meant self.image_title
?:
class PostImage(models.Model):
image = models.ImageField(null=False, blank=False, upload_to="images", default="default.png")
image_title = models.CharField(max_length=100, null=False, blank=False, default="")
slug = models.SlugField()
def save(self, *args, **kwargs):
self.slug = self.slug or slugify(self.image_title)
super().save(*args, **kwargs)
...
Unfortunately
Unfortunately, there is still something that will go wrong in your views, since you are trying to get a photo = PostImage.objects.get(slug=slug)
, but now slug
will be an actual slug, not an id. Easy to fix:
def viewImage(request, slug):
photo = PostImage.objects.get(slug=slug)
return render(request, 'viewimage.html', {'photo': photo, 'slug': slug})
And since you should never try to get an object without checking if it can be done first:
def viewImage(request, slug):
try:
photo = PostImage.objects.get(slug=slug)
except PostImage.DoesNotExist:
print("PostImage with this slug does not exist")
photo = None
return render(request, 'viewimage.html', {'photo': photo, 'slug': slug})