Vista basada en clases de Django: ¿Cómo paso parámetros adicionales al método as_view?

95

Tengo una vista personalizada basada en clases

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

Quiero pasar el parámetro slug (u otros parámetros a la vista) como este

MyView.as_view(slug='hello_world')

¿Necesito anular algún método para poder hacer esto?

Serjik
fuente

Respuestas:

113

Si su urlconf se parece a esto:

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

entonces el slug estará disponible dentro de sus funciones de vista (como 'get_queryset') así:

self.kwargs['slug']
Daniel Eriksson
fuente
18
Para evitar una excepción en caso de que este sea un parámetro opcional: useself.kwargs.get('slug', None)
Risadinha
6
Solo por curiosidad, ¿cuándo / dónde está poblado este "self.kwargs"? Estoy buscando la función de clase base donde se establece esto.
binithb
En github.com/django/django/blob/master/django/views/generic/… enclass View: def as_view(cls, **initkwargs): def view(request, *args, **kwargs):
Apollo Data
Sin responder la pregunta.
Kireeti K
Este método ahora está obsoleto, ahora puede usarurl('<slug:slug>', MyView.as_view(), name='my_named_view')
Rahat Zaman
91

Cada parámetro que se pasa al as_viewmétodo es una variable de instancia de la clase View. Eso significa que para agregar slugcomo parámetro, debe crearlo como una variable de instancia en su subclase:

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

Eso debería MyView.as_view(slug='hello_world')funcionar.

Si está pasando las variables a través de palabras clave, use lo que sugirió el Sr. Erikkson: https://stackoverflow.com/a/11494666/9903

holms
fuente
2
Nunca lo hagas import *. Editó su publicación.
holms
@holms para la ilustración de los futuros lectores, PEP8 dice " Deben evitarse las importaciones de comodines (desde <module> import )". Debería no es tan fuerte como debe y este es un ejemplo, pero sí, definitivamente * debería evitar las importaciones de comodines: python.org/dev/peps/pep-0008/#imports
Nada es obligatorio en ningún lugar, podemos romper cualquier cosa que queramos de la forma que queramos, pero pep8 es solo una recomendación de prácticas, y en la comunidad de Python es una regla general usar todas estas prácticas tanto como sea posible para evitar más problemas. Mi linter siempre está vacío cuando envío mi código :) pase lo que pase.
holms
¿Cuál es el valor de slug = 'hello_world' para una variable real?
Gonzalo Dambra
19

Vale la pena señalar que no necesita anular get_object()para buscar un objeto basado en un slug pasado como una palabra clave arg; puede usar los atributos de un SingleObjectMixin https://docs.djangoproject.com/en/1.5/ref/ vistas basadas en clases / 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_fieldy slug_url_kwargpredeterminado a 'slug')

Fush
fuente
1
¿Debería convertir mi respuesta en una respuesta wiki y agregarle su código?
15

Si desea agregar un objeto al contexto de la plantilla, puede anularlo get_context_datay agregarlo a su contexto. La solicitud también es parte de uno mismo en caso de que necesite 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
fuente
¿Qué es MyObject?
Rob Kwasowski
13

Puede pasar parámetros desde urls.py https://docs.djangoproject.com/en/1.7/topics/http/urls/#passing-extra-options-to-view-functions

Esto también funciona para vistas genéricas. Ejemplo:

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

En este caso, los parámetros pasados ​​a la vista no deben ser necesariamente variables de instancia de la clase Vista. Con este método, no necesita codificar el nombre de la página predeterminada en el modelo YourView, pero puede pasarlo como un parámetro de urlconf.

Yaroslav Nikitenko
fuente
gracias, estuve buscando esto durante bastante tiempo!
Ilja
7

Según lo indicado por Yaroslav Nikitenko , si usted no desea codificar una nueva variable de instancia de la clase View, puede pasar opciones adicionales para ver las funciones de urls.pyla siguiente manera:

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

Solo quería agregar cómo usarlo desde la vista. Puede implementar uno de los siguientes 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
fuente
1
Quería editar esto en la respuesta de Yaroslav Nikitenko , pero fue rechazado, así que hice el mío porque sentí que era la información que faltaba cuando la necesitaba.
Emile Bergeron
¡Gracias por tu publicación! No recuerdo si fui yo quien rechazó tu edición y por qué.
Yaroslav Nikitenko
@YaroslavNikitenko En retrospectiva, era demasiado grande para una edición y mejor como respuesta en forma de una nueva respuesta.
Emile Bergeron
@EmileBergeron La pregunta inicial fue sobre vistas genéricas como la DetailViewclase. ¿Podrías explicar cómo se usa allí?
bartaelterman
3

Para django 3.0, esto es lo que funcionó para mí:

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