Visão baseada em classe do Django: Como passo parâmetros adicionais para o método as_view?

95

Eu tenho uma visão baseada em classe personalizada

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

Eu quero passar o parâmetro slug (ou outros parâmetros para a visualização) assim

MyView.as_view(slug='hello_world')

Eu preciso substituir algum método para poder fazer isso?

Serjik
fonte

Respostas:

113

Se o seu urlconf for semelhante a este:

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

então o slug estará disponível dentro de suas funções de visualização (como 'get_queryset') assim:

self.kwargs['slug']
Daniel Eriksson
fonte
18
Para evitar uma exceção caso este seja um parâmetro opcional: useself.kwargs.get('slug', None)
Risadinha
6
Só por curiosidade, quando / onde esse "self.kwargs" é preenchido? Estou procurando a função de classe base onde isso está definido.
binithb
Em github.com/django/django/blob/master/django/views/generic/… emclass View: def as_view(cls, **initkwargs): def view(request, *args, **kwargs):
Apollo Data
Não respondendo à pergunta.
Kireeti K
Este método agora está obsoleto, agora você pode usarurl('<slug:slug>', MyView.as_view(), name='my_named_view')
Rahat Zaman
91

Cada parâmetro que é passado para o as_viewmétodo é uma variável de instância da classe View. Isso significa que, para adicionar slugcomo parâmetro, você deve criá-lo como uma variável de instância em sua subclasse:

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

Isso deve MyView.as_view(slug='hello_world')funcionar.

Se você estiver passando as variáveis ​​por meio de palavras-chave, use o que o Sr. Erikkson sugeriu: https://stackoverflow.com/a/11494666/9903

Holms
fonte
2
Nunca faça isso import *. Editou sua postagem.
holms
@holms para o esclarecimento de futuros leitores, PEP8 diz "Importações de curingas (de <module> import ) devem ser evitadas". Deveria não ser tão forte quanto deveria e este é um exemplo, mas sim definitivamente * deve evitar importações de curingas: python.org/dev/peps/pep-0008/#imports
Nada é obrigatório em qualquer lugar, podemos quebrar qualquer coisa que quisermos da maneira que quisermos, mas pep8 é apenas uma recomendação de práticas, e na comunidade python é uma regra usar todas essas práticas tanto quanto possível para evitar problemas futuros. Meu linter está sempre vazio quando eu envio meu código :) não importa o quê.
holms
Qual é o valor de slug = 'hello_world' para uma variável real?
Gonzalo Dambra
19

É importante notar que você não precisa substituir get_object()para procurar um objeto com base em um slug passado como uma palavra-chave arg - você pode usar os atributos de um 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 }}

(ambos slug_fielde o slug_url_kwargpadrão 'slug')

Fush
fonte
1
devo transformar minha resposta em uma resposta wiki e adicionar seu código a ela?
15

Se você deseja adicionar um objeto ao contexto do modelo, pode substituir get_context_datae adicionar ao seu contexto. A solicitação também faz parte de si mesmo , caso você precise do 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
fonte
O que é MyObject?
Rob Kwasowski
13

Você pode passar parâmetros de urls.py https://docs.djangoproject.com/en/1.7/topics/http/urls/#passing-extra-options-to-view-functions

Isso também funciona para visualizações genéricas. Exemplo:

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

Nesse caso, os parâmetros passados ​​para a visualização não devem ser necessariamente variáveis ​​de instância da classe Visualização. Usando este método, você não precisa codificar o nome da página padrão no modelo YourView, mas pode apenas passá-lo como um parâmetro do urlconf.

Yaroslav Nikitenko
fonte
obrigado, eu estava procurando por isso há um bom tempo!
Ilja
7

Como afirmado por Yaroslav Nikitenko , se você não quer para codificar uma nova variável de instância para a classe View, você pode passar opções extras para visualizar as funções da urls.pyseguinte forma:

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

Eu só queria acrescentar como usá-lo a partir da visualização. Você pode implementar um dos seguintes métodos:

# 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
fonte
1
Eu queria editar isso na resposta de Yaroslav Nikitenko , mas foi rejeitada, então fiz a minha porque senti que era a informação que faltava quando eu precisava dela.
Emile Bergeron,
Obrigado pelo seu post! Não me lembro se fui eu que rejeitei sua edição e por quê.
Yaroslav Nikitenko
@YaroslavNikitenko Em retrospecto, era muito grande para uma edição e melhor como uma resposta na forma de uma nova resposta.
Emile Bergeron
@EmileBergeron A pergunta inicial era sobre visões genéricas como a DetailViewclasse. Você poderia explicar como usá-lo aí?
bartaelterman
3

Para django 3.0, isto é o que funcionou para mim:

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