Vue basée sur les classes Django: comment passer des paramètres supplémentaires à la méthode as_view?

95

J'ai une vue personnalisée basée sur les classes

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

Je veux passer le paramètre slug (ou d'autres paramètres à la vue) comme ceci

MyView.as_view(slug='hello_world')

Dois-je remplacer des méthodes pour pouvoir le faire?

Serjik
la source

Réponses:

113

Si votre urlconf ressemble à quelque chose comme ceci:

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

alors le slug sera disponible dans vos fonctions d'affichage (telles que 'get_queryset') comme ceci:

self.kwargs['slug']
Daniel Eriksson
la source
18
Pour éviter une exception dans le cas où il s'agit d'un paramètre facultatif: utilisezself.kwargs.get('slug', None)
Risadinha
6
Juste curieux, quand / où est peuplé ce "self.kwargs"? Je recherche la fonction de classe de base où cela est défini.
binithb
Dans github.com/django/django/blob/master/django/views/generic/… dansclass View: def as_view(cls, **initkwargs): def view(request, *args, **kwargs):
Apollo Data
Je ne réponds pas à la question.
Kireeti K
Cette méthode est maintenant obsolète, vous pouvez maintenant l'utiliserurl('<slug:slug>', MyView.as_view(), name='my_named_view')
Rahat Zaman
91

Chaque paramètre passé à la as_viewméthode est une variable d'instance de la classe View. Cela signifie que pour ajouter en slugtant que paramètre, vous devez le créer en tant que variable d'instance dans votre sous-classe:

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

Cela devrait MyView.as_view(slug='hello_world')fonctionner.

Si vous passez les variables via des mots-clés, utilisez ce que M. Erikkson a suggéré: https://stackoverflow.com/a/11494666/9903

holms
la source
2
Ne fais jamais import *. J'ai modifié votre message.
holms
@holms pour éclairer les futurs lecteurs, PEP8 dit que "les importations de caractères génériques (à partir de l'importation <module> ) doivent être évitées". Ne devrait pas être aussi fort que nécessaire et ceci est un exemple mais oui certainement * devrait éviter les importations de caractères génériques: python.org/dev/peps/pep-0008/#imports
Rien n'est obligatoire n'importe où, nous pouvons casser tout ce que nous voulons de la manière que nous voulons, mais pep8 n'est qu'une recommandation de pratiques, et dans la communauté python, c'est une règle de base d'utiliser toutes ces pratiques autant que possible pour éviter d'autres problèmes. Mon linter est toujours vide lorsque je valide mon code :) quoi qu'il arrive.
holms
Quelle est la valeur de slug = 'hello_world' pour une variable réelle?
Gonzalo Dambra
19

Il convient de noter que vous n'avez pas besoin de remplacer get_object()pour rechercher un objet basé sur un slug passé comme mot-clé arg - vous pouvez utiliser les attributs d'un SingleObjectMixin https://docs.djangoproject.com/en/1.5/ref/ vues basées sur les classes / mixins-objet-unique / # 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 }}

(les deux slug_fieldet slug_url_kwargpar défaut 'slug')

Fush
la source
1
devrais-je transformer ma réponse en réponse wiki et y ajouter votre code?
15

Si vous souhaitez ajouter un objet au contexte du modèle, vous pouvez le remplacer get_context_dataet l'ajouter à son contexte. La requête fait également partie de self au cas où vous auriez besoin de 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
la source
Quoi MyObject?
Rob Kwasowski
13

Vous pouvez transmettre des paramètres depuis urls.py https://docs.djangoproject.com/en/1.7/topics/http/urls/#passing-extra-options-to-view-functions

Cela fonctionne également pour les vues génériques. Exemple:

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

Dans ce cas, les paramètres passés à la vue ne doivent pas nécessairement être des variables d'instance de la classe View. En utilisant cette méthode, vous n'avez pas besoin de coder en dur le nom de page par défaut dans le modèle YourView, mais vous pouvez simplement le passer en tant que paramètre d'urlconf.

Yaroslav Nikitenko
la source
merci, je cherchais ça depuis un bon moment!
Ilja
7

Comme l' a déclaré Yaroslav Nikitenko , si vous ne voulez pas coder une nouvelle variable d'instance à la classe View, vous pouvez passer des options supplémentaires pour afficher les fonctions de la urls.pymanière suivante:

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

Je voulais juste ajouter comment l'utiliser depuis la vue. Vous pouvez implémenter l'une des méthodes suivantes:

# 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
Émile Bergeron
la source
1
Je voulais éditer ceci dans la réponse de Yaroslav Nikitenko , mais elle a été rejetée, alors j'ai fait la mienne parce que je sentais que c'était l 'information manquante quand j'en avais besoin.
Emile Bergeron
Merci pour votre commentaire! Je ne me souviens pas si c'est moi qui ai rejeté votre modification et pourquoi.
Yaroslav Nikitenko
@YaroslavNikitenko Avec le recul, c'était trop gros pour une modification et le meilleur comme une réponse sous la forme d'une nouvelle réponse.
Emile Bergeron
@EmileBergeron La question initiale portait sur les vues génériques telles que la DetailViewclasse. Pourriez-vous expliquer comment l'utiliser là-bas?
bartaelterman
3

Pour django 3.0, c'est ce qui a fonctionné pour moi:

# 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
la source