Django dynamic ListView filtering problem

I am working on my first solo project with Django and I have hit a problem that no amount of searching and reading similar post on SO have solved.

I am trying to filter a gallery of images by their category, so that when the user clicks on a picture it will result in a page showing all the images with the same category. This will use HTMX hopefully in the final product, but I'm trying and failing to implement it using regular Django views initially.

As I said, this is my first solo project, so I'm very much a beginner, I know this isn't a debug service but just wanted some pointers on where I could be going wrong. Another set of eyes as you will.

I followed the docs on dynamic filtering CBV. I have overwritten get_queryset passing the Category slug into the kwargs and I have overwritten the get_context_dataso I can pass slug into the template.

I am getting a Reverse for 'select' with arguments '('',)' not found. 1 pattern(s) tried: ['select/(?P<slug>[-a-zA-Z0-9_]+)\\Z'] error, so I belive the problem is in my template/URLconf.

Models. Media with a FK to it's Category

class Category(models.Model):
    title = models.CharField(max_length=200, null=True)
    slug = AutoSlugField(populate_from='title')`

class Media(models.Model):
    timestamp = models.DateTimeField()
    image = models.ImageField(upload_to="media")
    url = models.URLField()
    order = models.IntegerField(default=0)
    visable = models.BooleanField(default=True)
    categories = models.ForeignKey(Category, on_delete=models.CASCADE, null=True, blank=True)

Views, IndexView is entire gallery and SelectView is image by category

class IndexView(ListView):

    template_name = "main/index.html"
    model = Media

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context ['main_images'] = Media.objects.filter(visable=True)
        return context


class SelectView(ListView):

    template_name = "main/select.html"
    model = Media

    def get_queryset(self):
        self.category = get_object_or_404(Category, title=self.kwargs['slug'])
        return Media.objects.filter(categories__title=self.category)

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['slug'] = self.category
        return context

URLconf with select being the relevant pattern.

app_name = "main"

urlpatterns = [
    path("", views.IndexView.as_view(), name="home"),
    path("about", views.AboutView.as_view(), name="about"),
    path("contact", views.ContactView.as_view(), name="contact"),
    path("select/<slug:slug>", views.SelectView.as_view(), name="select"),
]

Gallery template I have a for loop to display the IndexView. I think the problem is with the Href (which I want to take my to SelectView). I am passing slug in the {% url %} but think it should be image.categories__slug? I have tried this but it still doesn't work. I am stumped.


{% for image in main_images %}
        <div class="cbp-item web-design print"> 
<a href="{% url "main:select" slug %}" class="cbp-caption cbp-singlePageInline">

<div class="cbp-caption-defaultWrap"> <img src="{{ MEDIA_URL }} {{ image.image.url }}"alt=""> </div>
{% endfor %}

Many thanks.

I think what you want is to access the slug field on the image.categories field for each iteration.

{% for image in main_images %}
     ... 
     <a href="{% url 'main:select' image.cateogries.slug %}" class="cbp-caption cbp-singlePageInline">
     ...
{% endfor %}

In addition to that, I'd recommend that you do a lookup for the receiving slug instead of the title on the Category model. For example, if you should save I love this day as the title, the slug field would have I-love-this-day.

What you have:

def get_queryset(self):
    self.category = get_object_or_404(Category, title=self.kwargs['slug'])
    return Media.objects.filter(categories__title=self.category)

title=self.kwargs['slug'] won't find a title if your passing I-love-this-day as the slug. I'd suggest using slug=self.kwargs['slug']. See the below updates:

def get_queryset(self):
    # Also, the self keyword is not needed here either -> self.category
    category = get_object_or_404(Category, slug=self.kwargs['slug'])  # updated
    return Media.objects.filter(categories__title=category.title)  # updated

Additionally, I see where you're passing slug as a value via the context variable within the SelectView... I suggest you pass the category object explicitly via the context variable to the template where you can access the fields from your template if necessary.

Within the get_context_data():

def get_context_data(self, **kwargs):
    context = super().get_context_data(**kwargs)
    # context['slug'] = self.category
    context['category'] = get_object_or_404(Category, slug=self.kwargs['slug'])
    return context
Back to Top