Представление на основе классов Django: как передать дополнительные параметры методу as_view?

95

У меня есть настраиваемое представление на основе классов

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

Нужно ли мне переопределить какие-либо методы, чтобы это сделать?

Серджик
источник

Ответы:

113

Если ваш urlconf выглядит примерно так:

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

тогда слаг будет доступен внутри ваших функций просмотра (таких как get_queryset) следующим образом:

self.kwargs['slug']
Даниэль Эрикссон
источник
18
Чтобы избежать исключения в случае, если это необязательный параметр: используйтеself.kwargs.get('slug', None)
Рисадинья
6
Просто любопытно, когда / где заселился этот "self.kwargs"? Я ищу функцию базового класса, где это установлено.
binithb
В github.com/django/django/blob/master/django/views/generic/… inclass View: def as_view(cls, **initkwargs): def view(request, *args, **kwargs):
Apollo Data
Не отвечая на вопрос.
Kireeti K
Этот метод устарел, теперь его можно использоватьurl('<slug:slug>', MyView.as_view(), name='my_named_view')
Рахат Заман
91

Каждый параметр, передаваемый as_viewметоду, является переменной экземпляра класса View. Это означает, что для добавления slugв качестве параметра вы должны создать его как переменную экземпляра в своем подклассе:

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

Это должно MyView.as_view(slug='hello_world')сработать.

Если вы передаете переменные через ключевые слова, используйте то, что предложил г-н Эрикксон: https://stackoverflow.com/a/11494666/9903

Холмс
источник
2
Никогда не делай import *. Отредактировал свой пост.
Holms
@holms для просвещения будущих читателей, PEP8 говорит: « Следует избегать импорта подстановочных знаков (из импорта <module> )». Должен не так сильно, как должен, и это пример, но да, определенно * следует избегать импорта подстановочных знаков: python.org/dev/peps/pep-0008/#imports
Ничто не является обязательным в любом месте, мы можем сломать все, что захотим, любым способом, но pep8 - это всего лишь рекомендация методов, и в сообществе Python это практическое правило - использовать все эти методы как можно чаще, чтобы избежать дальнейших проблем. Мой линтер всегда пуст, когда я фиксирую свой код :) несмотря ни на что.
Holms
Какое значение slug = 'hello_world' для фактической переменной?
Гонсало Дамбра,
19

Стоит отметить, что вам не нужно переопределять get_object(), чтобы искать объект на основе slug, переданного как ключевое слово arg - вы можете использовать атрибуты SingleObjectMixin https://docs.djangoproject.com/en/1.5/ref/ представления на основе классов / 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 }}

(оба slug_fieldи по slug_url_kwargумолчанию 'slug')

Fush
источник
1
мне превратить свой ответ в ответ вики и добавить к нему ваш код?
15

Если вы хотите добавить объект в контекст для шаблона, вы можете переопределить get_context_dataи добавить в его контекст. Запрос также является частью self, если вам нужен 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
Алек Ландграф
источник
Что MyObject?
Роб Квасовски
13

Вы можете передавать параметры из urls.py https://docs.djangoproject.com/en/1.7/topics/http/urls/#passing-extra-options-to-view-functions

Это также работает для общих представлений. Пример:

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

В этом случае параметры, передаваемые в представление, не обязательно должны быть переменными экземпляра класса View. Используя этот метод, вам не нужно жестко указывать имя страницы по умолчанию в модели YourView, но вы можете просто передать его в качестве параметра из urlconf.

Ярослав Никитенко
источник
спасибо, долго искал это!
Ilja
7

Как заявил Ярослав Никитенко , если вы не хотите , чтобы жёстко новую переменную экземпляра в классе View, вы можете передать дополнительные опции для просмотра функций из urls.pyтак:

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

Я просто хотел добавить, как его использовать из представления. Вы можете реализовать один из следующих способов:

# 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
Эмиль Бержерон
источник
1
Я хотел отредактировать это в ответе Ярослава Никитенко , но он был отклонен, поэтому я сделал свой, потому что чувствовал, что это недостающая информация, когда мне это было нужно.
Эмиль Бержерон
Спасибо за ваше сообщение! Я не помню, был ли я тем, кто отклонил вашу правку, и почему.
Ярослав Никитенко
@YaroslavNikitenko Оглядываясь назад, я понимаю, что это было слишком много для редактирования и лучше всего в качестве ответа в виде нового ответа.
Эмиль Бержерон
@EmileBergeron Изначально вопрос касался общих представлений, таких как DetailViewкласс. Не могли бы вы объяснить, как его там использовать?
bartaelterman
3

Для django 3.0 у меня сработало следующее:

# 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'),
]
mizerablebr
источник