[Django]-Django class-based view: How do I pass additional parameters to the as_view method?

105👍

Every parameter that’s passed to the as_view method is an instance variable of the View class. That means to add slug as a parameter you have to create it as an instance variable in your sub-class:

# myapp/views.py
from django.views.generic import DetailView

class MyView(DetailView):
    template_name = 'detail.html'
    model = MyModel
    # additional parameters
    slug = None

    def get_object(self, queryset=None):
        return queryset.get(slug=self.slug)

That should make MyView.as_view(slug='hello_world') work.

If you’re passing the variables through keywords, use what Mr Erikkson suggested: https://stackoverflow.com/a/11494666/9903

125👍

If your urlconf looks something like this:

url(r'^(?P<slug>[a-zA-Z0-9-]+)/$', MyView.as_view(), name = 'my_named_view')

then the slug will be available inside your view functions (such as ‘get_queryset’) like this:

self.kwargs['slug']

19👍

It’s worth noting you don’t need to override get_object() in order to look up an object based on a slug passed as a keyword arg – you can use the attributes of a SingleObjectMixin https://docs.djangoproject.com/en/1.5/ref/class-based-views/mixins-single-object/#singleobjectmixin

# views.py
class MyView(DetailView):
    model = MyModel
    slug_field = 'slug_field_name'
    slug_url_kwarg = 'model_slug'
    context_object_name = 'my_model'

# urls.py
url(r'^(?P<model_slug>[\w-]+)/$', MyView.as_view(), name = 'my_named_view')

# mymodel_detail.html
{{ my_model.slug_field_name }}

(both slug_field and slug_url_kwarg default to 'slug')

👤Fush

16👍

You can pass parameters from urls.py
https://docs.djangoproject.com/en/1.7/topics/http/urls/#passing-extra-options-to-view-functions

This also works for generic views. Example:

url(r'^$', views.SectionView.as_view(), { 'pk': 'homepage', 'another_param':'?'}, name='main_page'),

In this case the parameters passed to the view should not necessarily be instance variables of the View class. Using this method you don’t need to hardcode default page name into YourView model, but you can just pass it as a parameter from urlconf.

15👍

If you want to add an object to the context for the template you can override get_context_data and add to its context. The request is also a part of self in case you need the request.user.

def get_context_data(self, **kwargs):
        context = super(MyTemplateView, self).get_context_data(**kwargs)
        if 'slug' in self.kwargs:
            context['object'] = get_object_or_404(MyObject, slug=self.kwargs['slug'])
            context['objects'] = get_objects_by_user(self.request.user)

        return context

9👍

As stated by Yaroslav Nikitenko, if you don’t want to hardcode a new instance variable to the View class, you can pass extra options to view functions from urls.py like this:

url(r'^$', YourView.as_view(), {'slug': 'hello_world'}, name='page_name')

I just wanted to add how to use it from the view. You can implement one of the following methods:

# If slug is optional
def the_function(self, request, slug=None):
    # use slug here

# if slug is an optional param among others
def the_function(self, request, **kwargs):
    slug = kwargs.get("slug", None)
    other_param = kwargs.get("other_param", None)

# If slug is required
def the_function(self, request, slug):
    # use slug here

4👍

For django 3.0, this is what worked for me:

# myapp/views.py
from django.views.generic import DetailView

class MyView(DetailView):
    template_name = 'detail.html'
    slug = None

    def get_object(self, queryset=None):
        self.slug = self.kwargs.get('slug', None)
        return queryset.get(slug=self.slug)

# myapp/urls.py
from django.urls import path
from . import views

urlpatterns = [
    path('slug/<slug:slug>/', views.MyView.as_view(), name='myview_by_tag'),
]

Leave a comment