Je suis nouveau sur Django Vues basées sur la classe. J'essaie de faire une vue simple pour obtenir les détails d'un message. Mon views.py:
from Django.views.generic import ListView, View, DetailView
class GenreDetail(DetailView):
model = Post
template_name = "post.html"
Mon urls.py:
urlpatterns = [
url(r'(?P<post_id>[^/]+)', GenreDetail.as_view(), name = 'post'),
url(r'(?P<post_id>[^/]+)/(?P<slug>[-\w]+)$', GenreDetail.as_view()),
]
Erreur que j'obtiens:
AttributeError at /2/memoirs-of-a-geisha-by-arthur-golden
Generic detail view GenreDetail must be called with either an object pk or a slug.
Le pk ou le slug n'est donc pas transmis à la vue de détail générique. Comment passer ça? Je suppose qu'à partir de l'URL, il peut reprendre mais ce n'est pas le cas.
les modèles d'url sont vérifiés dans l'ordre dans lequel vous les définissez
alors voici:
urlpatterns = [
url(r'(?P<post_id>[^/]+)', GenreDetail.as_view(), name = 'post'),
url(r'(?P<post_id>[^/]+)/(?P<slug>[-\w]+)$', GenreDetail.as_view()),
]
... le premier motif est mis en correspondance (car il ne se termine pas par $
donc le segment supplémentaire est juste ignoré)
... et ce modèle ne transmet qu'un seul mot clé arg
En général, c'est une mauvaise idée d'avoir plusieurs modèles d'url pointant vers la même vue. Si possible, vous devriez essayer de créer une seule expression régulière (par exemple en utilisant groupes optionnels ) qui gère les différents cas de l'URL pour une vue particulière. C'est plus explicite de cette façon.
D'un autre côté, inverser simplement l'ordre de vos modèles pour mettre le plus explicite en premier fonctionnerait également et serait correct (c'est la règle Django des urlpatterns!)
urlpatterns = [
url(r'(?P<post_id>[^/]+)/(?P<slug>[-\w]+)$', GenreDetail.as_view()),
url(r'(?P<post_id>[^/]+)', GenreDetail.as_view(), name = 'post'),
]
Comme @ozgur le mentionne, vous devez également indiquer à la vue d'utiliser post_id
au lieu de pk
en définissant pk_url_kwarg
Si vous souhaitez récupérer des détails à l'aide de post_id ou slug, vos URL doivent être comme ceci
url(r'post/(?P<post_id>\d+)/$', GenreDetail.as_view(), name = 'post_detail'),
url(r'post/(?P<slug>[-\w]+)/$', GenreDetail.as_view(), name = 'post_detail_slug'),
Et votre vue devrait être comme ça
from Django.views.generic import DetailView
class GenreDetail(DetailView):
model = Post
template_name = "post.html"
pk_url_kwarg = "post_id"
slug_url_kwarg = 'slug'
query_pk_and_slug = True
Pour plus de détails, veuillez lire le docs .
Le problème est que vous devez dire à DetailView
qu'il doit utiliser post_id
mot-clé dans l'URL au lieu de ceux par défaut pk
ou slug
afin d'obtenir l'objet qui sera affiché.
Cela peut être fait en définissant pk_url_kwarg
attribut:
(Votre définition d'URL est également erronée, terminez toujours vos définitions d'URL par $
. Ci-dessous la version corrigée)
url(r'(?P<post_id>\d+)$', GenreDetail.as_view(), name = 'post'),
url(r'(?P<post_id>\d+)/(?P<slug>[-\w]+)$', GenreDetail.as_view()),
Les URL suivantes correspondront compte tenu des modèles d'URL ci-dessus:
from Django.views.generic import DetailView
class GenreDetail(DetailView):
model = Post
template_name = "post.html"
pk_url_kwarg = "post_id"
Alternativement, vous pouvez simplement modifier post_id
à pk
dans votre URL pour que vous n'ayez rien à toucher dans votre vue:
url(r'(?P<pk>\d+)$', GenreDetail.as_view(), name = 'post'),
url(r'(?P<pk>\d+)/(?P<slug>[-\w]+)$', GenreDetail.as_view()),
En utilisant chemin :
from Django.urls import path
from . import views
urlpatterns = [
path('<pk>/', views.GenreDetail.as_view(), name="post")]
Pour slug
:
path('<slug:slug>/', views.GenreDetail.as_view(), name="post")