基于 Django 类的视图: 如何向 as_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)

我想像这样传递 slug 参数(或者其他参数到视图中)

MyView.as_view(slug='hello_world')

我需要重写任何方法才能做到这一点吗?

108451 次浏览

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

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

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

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

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.

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

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