Widok oparty na klasach Django: jak przekazać dodatkowe parametry do metody as_view?

95

Mam niestandardowy widok oparty na klasach

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

Chcę przekazać parametr slug (lub inne parametry do widoku) w ten sposób

MyView.as_view(slug='hello_world')

Czy muszę zastąpić jakieś metody, aby to zrobić?

Serjik
źródło

Odpowiedzi:

113

Jeśli twój urlconf wygląda mniej więcej tak:

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

wtedy slug będzie dostępny w twoich funkcjach widoku (takich jak „get_queryset”) w ten sposób:

self.kwargs['slug']
Daniel Eriksson
źródło
18
Aby uniknąć wyjątku w przypadku, gdy jest to parametr opcjonalny: użyjself.kwargs.get('slug', None)
Risadinha
6
Ciekawe, kiedy / gdzie jest to „self.kwargs”? Szukam funkcji klasy bazowej, gdzie jest to ustawione.
binithb
Na github.com/django/django/blob/master/django/views/generic/ ... inclass View: def as_view(cls, **initkwargs): def view(request, *args, **kwargs):
Apollo Data
Nie odpowiadając na pytanie.
Kireeti K
Ta metoda jest teraz przestarzała, teraz możesz jej używaćurl('<slug:slug>', MyView.as_view(), name='my_named_view')
Rahat Zaman
91

Każdy parametr przekazany do as_viewmetody jest zmienną wystąpienia klasy View. Oznacza to, że aby dodać slugjako parametr, musisz utworzyć go jako zmienną instancji w swojej podklasie:

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

To powinno MyView.as_view(slug='hello_world')działać.

Jeśli przepuszczasz zmienne przez słowa kluczowe, użyj tego, co zasugerował pan Erikkson: https://stackoverflow.com/a/11494666/9903

Holms
źródło
2
Nigdy tego nie rób import *. Edytował Twój post.
holms
@holms dla oświecenia przyszłych czytelników, PEP8 mówi: „ Należy unikać importu symboli wieloznacznych (z importu <module> )”. Powinno nie być tak mocne, jak to konieczne i to jest przykład, ale tak zdecydowanie * powinno unikać importu symboli wieloznacznych: python.org/dev/peps/pep-0008/#imports
Nic nie jest nigdzie obowiązkowe, możemy zepsuć wszystko, co chcemy, w dowolny sposób, ale pep8 to tylko zalecenie praktyk, aw społeczności Pythona jest to praktyczna zasada, aby używać wszystkich tych praktyk w jak największym stopniu, aby uniknąć dalszych problemów. Mój linter jest zawsze pusty, kiedy zatwierdzam swój kod :) bez względu na wszystko.
holms
Jaka jest wartość slug = 'hello_world' dla rzeczywistej zmiennej?
Gonzalo Dambra
19

Warto zauważyć, że nie trzeba nadpisywać get_object(), aby wyszukać obiekt na podstawie slugu przekazanego jako słowo kluczowe arg - możesz użyć atrybutów SingleObjectMixin https://docs.djangoproject.com/en/1.5/ref/ widoki oparte na klasach / 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 }}

(oba slug_fieldi slug_url_kwargdomyślnie 'slug')

Fush
źródło
1
czy mam zamienić swoją odpowiedź na odpowiedź wiki i dodać do niej Twój kod?
15

Jeśli chcesz dodać obiekt do kontekstu szablonu, możesz nadpisać get_context_datai dodać do jego kontekstu. Żądanie jest również częścią siebie na wypadek, gdybyś potrzebował 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
Aleck Landgraf
źródło
Co MyObject?
Rob Kwasowski
13

Możesz przekazać parametry z urls.py https://docs.djangoproject.com/en/1.7/topics/http/urls/#passing-extra-options-to-view-functions

Działa to również w przypadku widoków ogólnych. Przykład:

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

W takim przypadku parametry przekazywane do widoku nie muszą być koniecznie zmiennymi instancji klasy View. Korzystając z tej metody, nie musisz zakodować na stałe domyślnej nazwy strony w modelu YourView, ale możesz po prostu przekazać ją jako parametr z urlconf.

Jarosław Nikitenko
źródło
dziękuję, szukałem tego dość długo!
Ilja
7

Jak stwierdził Jarosław Nikitenko , jeśli nie chcesz zakodować na stałe nowej zmiennej instancji w klasie View, możesz przekazać dodatkowe opcje, aby wyświetlić funkcje z urls.pytakich sposobów :

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

Chciałem tylko dodać, jak go używać z widoku. Możesz zaimplementować jedną z następujących metod:

# 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
Emile Bergeron
źródło
1
Chciałem to zmienić w odpowiedzi Jarosława Nikitenki , ale została odrzucona, więc stworzyłem własną, ponieważ czułem, że to brakująca informacja, kiedy jej potrzebowałem.
Emile Bergeron
dziękuję za twój post! Nie pamiętam, czy to ja odrzuciłem twoją edycję i dlaczego.
Jarosław Nikitenko
@YaroslavNikitenko Z perspektywy czasu był on zbyt duży na edycję i najlepszy jako odpowiedź w formie nowej odpowiedzi.
Emile Bergeron,
@EmileBergeron Pierwsze pytanie dotyczyło ogólnych poglądów, takich jak DetailViewklasa. Czy mógłbyś wyjaśnić, jak go tam używać?
bartaelterman
3

W przypadku django 3.0 zadziałało to:

# 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
źródło