How to add multiple slugs into one url path in Django 2.1?

Viewed 4882

I want to have a URL path like this: www.example.com/bachelor/frankfurt-university/corporate-finance

As you can see, the URL path includes 3 slugs in this example.

I have 3 different class for these categories. And slug is included inside each of them separately. What do I need to do in order to be able to achieve that type of URL paths? I can make URL path with a single slug but not with multiple slugs.

Every single help or thought is highly appreciated. I can't find any source for that.

URLS.py

app_name = 'mnsdirectory'
urlpatterns = [
    path('', views.IndexView.as_view(), name='index'), #views.index
    path('study/<slug:studylevelslug>/<slug:subjectslug>/', views.SubjectDetailView.as_view(), name='subject-detail'),
    path('study-abroad/<slug:studylevelslug>/', views.StudylevelDetailView.as_view(), name='studylevel-list'),
    ]

VIEWS.py

class IndexView(generic.ListView):
    model = Programmesearch
    template_name = 'mnsdirectory/index.html'
    context_object_name = 'universities'
    queryset = Programmesearch.objects.all()[:6]
    def get_context_data(self, **kwargs):
        context = super(IndexView, self).get_context_data(**kwargs)
        context['studylevels'] = StudyLevel.objects.all()[:10]
        return context

class SubjectDetailView(generic.DetailView):
    model = Programmesearch
    template_name = 'mnsdirectory/subject_detail.html'
    slug_field = 'subjectslug'
    slug_url_kwarg = 'subjectslug'

class StudylevelDetailView(generic.DetailView):
    model = StudyLevel
    template_name = 'mnsdirectory/study_level.html'
    slug_field = 'studylevelslug'
    slug_url_kwarg = 'studylevelslug'

MODELS.py

class Programmesearch(models.Model):
    study_country = models.CharField(max_length=100, 
        choices=COUNTRY_CHOICE)
    full_subject_name = models.CharField(max_length=100, blank=True, 
        null=True)

    def get_unique_slug(self):
        subjectslug = slugify(self)
        unique_slug = subjectslug
        counter = 1
        while mnsdirectory.objects.filter(subjectslug = unique_slug).exists():
            unique_slug = '{}-{}'.format(subjectslug, counter)
            counter += 1
        return unique_slug

    subjectslug = models.SlugField(unique=True)

    def __str__(self):
        return self.subjectslug

    def get_absolute_url(self):
        return reverse('SubjectDetailView', args=[str(self.id)])

def pre_save_programmesearch_receiver(sender, instance, *args, **kwargs):
    subjectslug = slugify(instance.full_subject_name)
    exists = Programmesearch.objects.filter(subjectslug=subjectslug).exists()
    if exists:
        subjectslug = "%s-%s" %(subjectslug, instance.id)
    instance.subjectslug = subjectslug

pre_save.connect(pre_save_programmesearch_receiver, sender=Programmesearch)

class StudyLevel(models.Model):
    title = models.CharField(max_length=100, blank=True, null=False)
    studylevelslug = models.SlugField(unique=True, editable=False, max_length=100)

    def __str__(self):
        return self.studylevelslug

    def get_absolute_url(self):
        return reverse('StudylevelDetailView', args=[str(self.id)])

    def get_unique_slug(self):
        studylevelslug = slugify(self.study_level)
        unique_slug = studylevelslug
        counter = 1
        while StudyLevel.objects.filter(studylevelslug = unique_slug).exists():
            unique_slug = '{}-{}'.format(studylevelslug, counter)
            counter += 1
        return unique_slug

def pre_save_studylevel_receiver(sender, instance, *args, **kwargs):
    studylevelslug = slugify(instance.study_level)
    exists = StudyLevel.objects.filter(studylevelslug=studylevelslug).exists()
    if exists:
        studylevelslug = "%s-%s" %(studylevelslug, instance.id)
    instance.studylevelslug = studylevelslug

pre_save.connect(pre_save_studylevel_receiver, sender=StudyLevel)
2 Answers

I had the same problem, you can store and pass your first slug slug:studylevelslug(use session or save it as a fields in your model) then pass multi slug to your url path same as you did in your code : path('study/<slug:studylevelslug>/<slug:subjectslug>/', views.SubjectDetailView.as_view(), name='subject-detail'), in your template when you call {% url %} pass your slugs like this :

{% url 'subject-detail' studylevelslug=YOURFIRSTSLUG subjectslug=YOURSECONDSLUG  %}

I used this in my project and it worked completely fine. for more detail about how store your slug in session use this link: How use session in Django

if you need any further help, ask and will happy to help.

A DetailView is for a single object so you cannot have it with 2 models.

Try something like this:

class SubjectDetailView(generic.DetailView):
    model = Programmesearch
    template_name = 'mnsdirectory/subject_detail.html'
    slug_field = 'studylevelslug'
    slug_url_kwarg = 'studylevelslug'

    def get_study_level(self, *args, **kwargs):
        return StudyLevel.objects.get(slug=subjectslug)

    def get_context_data(self, *args, **kwargs):
        ctx = super().get_context_data(*args, **kwargs)
        ctx['study_level'] = self.get_study_level()
        return ctx

You'll now have access to object and study_level within your template. object will hold your Programmsearch data and study_level your StudyLevel data

Related