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

105,410

Solution 1

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

Solution 2

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']

Solution 3

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')

Solution 4

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

Solution 5

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.

Share:
105,410

Related videos on Youtube

Serjik
Author by

Serjik

[![alt text][1]][2][![alt text][3]][4] [3]: https://i.stack.imgur.com/N4O1Z.jpg?s=32 (Personal Website (Resume)) [4]: https://serj1975.pythonanywhere.com

Updated on May 28, 2020

Comments

  • Serjik
    Serjik almost 4 years

    I have a custom class-based view

    # myapp/views.py
    from django.views.generic import *
    
    class MyView(DetailView):
        template_name = 'detail.html'
        model = MyModel
    
        def get_object(self, queryset=None):
            return queryset.get(slug=self.slug)
    

    I want to pass in the slug parameter (or other parameters to the view) like this

    MyView.as_view(slug='hello_world')
    

    Do I need to override any methods to be able to do this?

  • Admin
    Admin almost 11 years
    should I turn my answer into a wiki answer and add your code to it?
  • Risadinha
    Risadinha over 9 years
    To avoid an exception in case this is an optional parameter: use self.kwargs.get('slug', None)
  • binithb
    binithb over 8 years
    Just curious, when/where is this "self.kwargs" populated ? I am looking for the base class function where this is set .
  • Emile Bergeron
    Emile Bergeron over 7 years
    I wanted to edit this in Yaroslav Nikitenko's answer, but it was rejected, so I made my own because I felt it was the missing information when I needed it.
  • Emile Bergeron
    Emile Bergeron over 7 years
    @YaroslavNikitenko In hindsight, it was too big for an edit and best as a reply in the form of a new answer.
  • Apollo Data
    Apollo Data almost 7 years
    In github.com/django/django/blob/master/django/views/generic/… in class View: def as_view(cls, **initkwargs): def view(request, *args, **kwargs):
  • holms
    holms about 6 years
    Never do import *. Edited your post.
  • Admin
    Admin about 6 years
    @holms for the enlightenment of future readers, PEP8 says "Wildcard imports (from <module> import ) should be avoided". Should isn't as strong as must and this is an example but yes definitely *should avoid wildcard imports: python.org/dev/peps/pep-0008/#imports
  • holms
    holms about 6 years
    Nothing is a must anywhere, we can break anything we want in any way we want, but pep8 is just recommendation of practices, and in python community it's a rule of thumb to use all of these practices as much as possible to avoid further problems. My linter is always empty when I commit my code :) no matter what.
  • bartaelterman
    bartaelterman over 5 years
    @EmileBergeron The initial question was about generic views such as the DetailView class. Could you explain how to use it there?
  • Kireeti K
    Kireeti K over 5 years
    Not answering the question.
  • Rahat Zaman
    Rahat Zaman about 5 years
    This method is now deprecated, now you can use url('<slug:slug>', MyView.as_view(), name='my_named_view')
  • Rob Kwasowski
    Rob Kwasowski almost 5 years
    What's MyObject?
  • Gonzalo Dambra
    Gonzalo Dambra almost 4 years
    What's the value of slug='hello_world' for an actual variable?
  • Aagam Sheth
    Aagam Sheth over 3 years
    I guess that slug is a class variable and not an instance variable here.
  • Ali Rn
    Ali Rn almost 3 years
    Just updated the link for Django 3.2: docs.djangoproject.com/en/3.2/topics/http/urls/…
  • kiloton
    kiloton over 2 years
    Is there a way to make these extra parameters available to all HTTP methods in the class based views? Right now I'm doing get(self, request, model: Model): pass, put(self, request, model: Model): pass, etc. If I could assign and type 'model' in one place it would be neater.
  • Emile Bergeron
    Emile Bergeron over 2 years
    @kiloton you should ask a new question if searching the documentation and Stack Overflow didn't solve your issue.