Categories slug

Hello, i hope i can get some help or advice.

The question is simple. How do i put all categories slug into a url?

Let’s say we are adding categories via django admin.

  1. Man clothes
  2. Jackets
  3. Black jackets

That is just an example.

But in the shop, we need to have website.com/shop/man-clothes/jackets/black-jackets/
They will show their subcategories if they exist, and products.

Thank you

did you find this?

# urls.py
urlpatterns = [
  path('<str:a>/<str:b>/<str:c>/', views.do),
  or
  path('<slug:a>/<slug:b>/<slug:c>/', views.do),
]
# views.py
def aaa(request, a, b, c):
  slug_a = Tag.objects.get(slug=a)
  slug_b = Tag.objects.get(slug=b)
  slug_c = Tag.objects.get(slug=c)
  queryset = Model.objects.filter(slug=slug_a, slug=slug_b, slug=slug_c)
  ...

I think you’re saying that if you have a detail view for a single category (Black jackets) you want to have its URL also include the slugs for its parent categories.

I’ve done it like this in a similar situation…

In my urls.py:

from django.urls import path, re_path
from .views import CategoryDetailView

urlpatterns = [
    # This must be last in the list because it will catch almost everything remaining:
    re_path(
        r"^shop/(?P<slugs>[\w\/-]+)/$", CategoryDetailView.as_view(), name="category_detail"
    ),
]

And then my views.py:

from django.views.generic.detail import DetailView
from .models import Category

class CategoryDetailView(DetailView):
    model = Category
    slug_url_kwarg = "slugs"

    def get_object(self, queryset=None):
        """
        Get the Category from the `slugs`, which could be like
        "man-clothes/jackets/black-jackets/"

        Category.slug is not unique, so we first try to find a Category
        using both its own slug ("black-jackets") and its depth (3, here).

        But that might find more than one Category, in which case we
        must also use its parents to narrow things down.
        """
        obj = None

        slugs = self.kwargs.get(self.slug_url_kwarg, None)

        if slugs is None:
            raise AttributeError("'CategoryDetailView' must be called with slugs in the URL")
        else:
            slugs_arr = slugs.split("/")
            slug = slugs_arr[-1]  # slug of this category
            depth = len(slugs_arr)

        categories = Category.objects.filter(slug=slug, depth=depth)

        if len(categories) == 1:
            obj = categories.first()
        elif len(categories) > 1:
            # Multiple categories with this slug+depth, so find which
            # category has a parent matching the next slug up.
            for category in categories:
                parent = category.get_parent()
                if parent.slug == slugs_arr[-2]:
                    obj = category
                    break

        if obj is None:
            raise Http404("No Categories found matching the query")
        else:
            return obj

BUT, note that this assumes the Category model also has a depth parameter indicating how deep in the “tree” it is. I’m using django-treebeard for my category hierarchy (I recommend it!) and my Category model is like this:

from treebeard.mp_tree import MP_Node
from django.db import models

class Category(models.Model, MP_Node):
    title = models.CharField(max_length=255, blank=False, null=False)
    slug = models.SlugField(max_length=50, blank=False, null=False)

However, this leaves out one thing – how do you generate the URL for a Category, including all of its parent Categories’ slugs? The Category model’s get_absolute_url() method looks like this, using django-treebeard’s get_ancestors() method:

    def get_absolute_url(self):
        # Join all the parent categories' slugs, eg:
        # 'man-clothes/jackets/black-jackets'.
        parent_slugs = "/".join([c.slug for c in self.get_ancestors()])

        # If there are no parent slugs, it's a top-level category.
        path = f"{parent_slugs}/{self.slug}" if parent_slugs else self.slug

        return reverse("category_detail", kwargs={"slugs": path})

This looks like it would fail to fetch some data in the case that there are two categories sharing the parent__slug and slug. Like if we had women-clothes/jackets/black-jackets and men-clothes/jackets/black-jackets which it is possible to get in such a UrlConf. In this case there are multiple categories matching the same parent-slug.

Yes, that’s true - in my case I knew I wouldn’t have that problem. But you could extend the logic in the view to make it more robust for your site.

Thank you all for answering, i was away but i saw the responses, will try and get back :slight_smile: