DJANGO Generic Views: How to use reverse() in get_absolute_url method? - django

I'm trying to implement generic editing views as shown here:
I started with the CreateView which renders and submits data correctly. However, I am getting an error when I tries to use reverse() to return to the detail view page for the new object.
Here is my Error message:
NoReverseMatch at /work/clients/create/
Reverse for 'ClientDetailView' with arguments '('14',)' and keyword arguments '{}' not found. 0 pattern(s) tried: []
Here is how I defined get_absolute_url() in my model:
def get_absolute_url(self):
return reverse('ClientDetailView', kwargs={'pk': self.pk})
My view is called ClientDetailView. I'm not sure what other information would be helpful.
Here is class ClientDetailView:
class ClientDetailView(generic.DetailView):
model = Client
template_name = 'work/client_detail.html'`
and here is url() from urls.py:
url(r'^clients/(?P<pk>[0-9]+)/$', views.ClientDetailView.as_view(), name='clients_detail'),`
Can anyone explain what I am doing wrong?

I solved my own problem. I had to add the namespace to the reverse() method:
return reverse('work:clients_detail', kwargs={'pk': self.pk})
I would appreciate if someone else could explain why I needed to do this.
Here is the my complete urls.py:
from django.conf.urls import url
from . import views
app_name = 'work'
urlpatterns = [
url(r'^work_orders/$', views.WorkOrdersIndexView.as_view(), name='quotes_index'),
url(r'^work_orders/(?P<pk>[0-9]+)/$', views.WorkOrdersDetailView.as_view(), name='work_orders_detail'),
url(r'^quotes/$', views.QuotesIndexView.as_view(), name='quotes_index'),
url(r'^quotes/(?P<pk>[0-9]+)/$', views.QuotesDetailView.as_view(), name='quotes_detail'),
url(r'^project/(?P<pk>[0-9]+)/$', views.ProjectDetailView.as_view(), name='project_detail'),
url(r'^project/create/$', views.ProjectCreateView.as_view(), name='project_create'),
url(r'^project/(?P<pk>[0-9]+)/update/$', views.ProjectUpdateView.as_view(), name='project_update'),
url(r'^project/(?P<pk>[0-9]+)/delete/$', views.ProjectDeleteView.as_view(), name='project_delete'),
url(r'^clients/$', views.ClientView.as_view(), name='client_index'),
url(r'^clients/(?P<pk>[0-9]+)/$', views.ClientDetailView.as_view(), name='clients_detail'),
url(r'^clients/create/$', views.ClientCreateView.as_view(), name='client_create'),
url(r'^clients/(?P<pk>[0-9]+)/update/$', views.ClientUpdateView.as_view(), name='clients_update'),
url(r'^clients/(?P<pk>[0-9]+)/delete/$', views.ClientDeleteView.as_view(), name='clients_delete'),
]

actually you are trying to reverse the view, instead of ClientDetailView
use url name clients_detail

Related

Wagtail: Add method to PageModel to get an inspect url

I am trying to add a dynamic instead of a hard coded get_inspect_url method to a PageModel:
class MyModel(Page):
# ...
# this is what I have now, which breaks in prod due to a different admin url
def get_inspect_url(self):
inspect_url = f"/admin/myapp/mymodel/inspect/{self.id}/"
return inspect_url
I know that you can use the ModelAdmin.url_helper_class in wagtail_hooks.py to get admin urls for an object, but I can't figure a way to do the same on the model level as a class method. Is there a way?
thanks to #Andrey Maslov tip I found a way:
from django.urls import reverse
def get_inspect_url(self):
return reverse(
f"{self._meta.app_label}_{self._meta.model_name}_modeladmin_inspect",
args=[self.id],
)
The basic form of a Wagtail admin url is:
[app_label]_[model_name]_modeladmin_[action]
Just change the [action] to one of the following to generated other instance level admin urls:
edit
delete
if you have in you urls.py line like this
path(MyModel/view/<id:int>/', YourViewName, name='mymodel-info'),
then you can add to your models.py this lines
from django.urls import reverse
...
class MyModel(Page):
def get_inspect_url(self):
inspect_url = reverse('mymodel-info', kwargs={'id': self.id})
return inspect_url

RedirectView give NoReverseMatch

Recently I've changed the paths of the blog posts to give more legible the urls.
Before I've this paths:
path("category/<slug:slug_category>/", views.singleCategory_postList, name="single_category"),
path("<slug:slug_post>/", views.singlePost, name='single_blog_post'),
Now I've this:
path("<slug:slug_category>/", views.singleCategory_postList, name="single_category"),
path("<slug:slug_category>/<slug:slug_post>/", views.singlePost, name='single_blog_post'),
Before get_absolute_url was this:
class Category(models.Model):
.....
def get_absolute_url(self):
return reverse("single_category", kwargs={"slug_category": self.slug_category})
class BlogPost(ModelPost, TimeManager):
.....
def get_absolute_url(self):
return reverse("single_blog_post", kwargs={"slug_post": self.slug_post})
Now is this:
class Category(models.Model):
.....
def get_absolute_url(self):
return reverse("single_category", kwargs={"slug_category": self.slug_category})
class BlogPost(ModelPost, TimeManager):
.....
def get_absolute_url(self):
return reverse("single_blog_post", kwargs={
"slug_post": self.slug_post,
"slug_category": self.category.slug_category,
})
I'm trying to use the RedirectView for redirect all the old paths; then into urls.py I've this now:
path("category/<slug:slug_category>/", RedirectView.as_view(pattern_name='single_category', permanent=True)),
path("<slug:slug_post>/", RedirectView.as_view(pattern_name='single_blog_post', permanent=True)),
path("categorie/", views.categoryList, name="list_category"),
path("<slug:slug_category>/", views.singleCategory_postList, name="single_category"),
path("", views.postList, name='list_post'),
path("<slug:slug_category>/<slug:slug_post>/", views.singlePost, name='single_blog_post'),
When I use those RedirectView it's shown me this error:
NoReverseMatch at /blog/gis/
Reverse for 'single_blog_post' with keyword arguments '{'slug_post':
'gis'}' not found. 1 pattern(s) tried:
['blog\/(?P[-a-zA-Z0-9_]+)\/(?P[-a-zA-Z0-9_]+)\/$']
If I comment the two RedirectView paths the error disappear and I can use the site without problems but when I use the old paths I see 404 error.
I don't have understood how RedirectView works. Someone can give me an example?
The problem is that your old view only required the post slug, but your new one additionally requires the category slug. However, there's no way a simple RedirectView can do this redirection, because it can only look at the arguments passed in the original URL itself. It doesn't know how to go to the database to find the category slug and use it in the redirection.
So, you'll need to write the redirect view yourself. It could be pretty simple:
def redirect_with_category(request, slug):
post = get_object_or_404(Post, slug=slug)
return redirect(post, permanent=True)
Note that redirect will automatically call the get_absolute_url method of the Post. Also note you want to use permanent=True to return a 301 rather than a 302.

NoReverseMatch error while redirecting to results page

I have intended to write an search application by Django.
I am getting a NoReverseMatch error when I redirect to results page.
I posted my codes here http://pastebin.com/AL4rG9NU
Or you can read it below
urls.py
urlpatterns = patterns('pylucene.views',
(r'^$', 'index'),
(r'^search/$', 'search'),
)
views.py
def index(request):
return render_to_response('pylucene/index.html', context_instance=RequestContext(request))
def search(request):
query = request.POST['query']
search_results = search_files(query)
return HttpResponseRedirect(reverse('pylucene.views.results', args=(search_results,)))
The Error:
NoReverseMatch at /pylucene/search/
Reverse for 'pylucene.views.results' with arguments
'([(u'Documents\\Dieu khien may tinh bang y nghi.txt', u'Dieu khien
may tinh bang y nghi.txt'), '1 total matching documents.'],)' and
keyword arguments '{}' not found.
def results(request, search_results):
return render_to_response('pylucene/results.html', {'search_results': search_results}, context_instance=RequestContext(request))
I read several similar topics but I can not solve my problem.
Please help me.
Thank you so much.
I think that you are not undestanding how the reverse function works and what are you trying is just not posible.
For the reverse function your url must be declared on urls.py for example:
#urls.py:
urlpatterns = patterns('blog.views',
(r'^$', 'index'),
url(r'^blog/(?P<slug>\d{4})/$', 'blog', name="blog-detail"),
)
Now in your code you can do
reverse('blog-detail', args=('django-urls',))
# the resolt of this is
# /blog/django-urls/
And this is how reverse works.
The real answer
I think that you do not need 2 views, but if you really want to: you have to do this to pass all the query already performed
def search(request):
query = request.POST['query']
search_results = search_files(query)
return results(request, search_results)
but i think that the best that you can do is this (using GET):
def search(request):
query = request.GET['query'] # I think using get is better because you are GETing info
search_results = search_files(query) # better if returns a generator
return render_to_response('pylucene/results.html',
{'search_results': search_results},
context_instance=RequestContext(request)

Getting #permalink decorator to work with django generic views?

Maybe I am missing something, but according to the django docs (1.2), I have setup my URLS models exactly as specified to ensure I am not hard-coding urls returned for get_absolute_url.
Here's what I have:
in urls.py
urlpatterns = patterns('django.views.generic.list_detail',
url(r'^$','object_list',
{ 'queryset': product.objects.all(),
'template_name': 'products/list.html',
},
name='product_list'),
url(r'^(?P<slug>[-\w]+)/$','object_detail',
{ 'queryset': product.objects.all(),
'template_name': 'products/detail.html',
},
name='product_detail'),
)
in models.py
#models.permalink
def get_absolute_url(self):
return ('product_detail', (), {'slug': str(self.slug)})
The method returns an empty string in the templates, and from the shell it gives an error.
NoReverseMatch: Reverse for 'product_detail' with arguments '()' and keyword arguments '{'slug': 'dd-d--'}' not found.
This should resolve should it not, since urls.py has a name : product_detail?
Syntax seems to be correct, are you sure your urls.py gets included? Try stepping in debuggin in view code and use reverse function first to generate the url.
My blind guess would be, something is wrong with your urls.py file in general.
Try changing this line:
url(r'(?P<slug>[-\w]+)/^$','object_detail',
to
url(r'^(?P<slug>[-\w]+)/$','object_detail',
Carret (^) stands for beginning of the line, so it is illogical in the context you wrote it since it means the line has content before it even begins.

Problem using generic views in django

I'm currently working with django generic views and I have a problem I can't figure out.
When using delete_object I get a TypeError exception:
delete_object() takes at least 3 non-keyword arguments (2 given)
Here is the code (I have ommited docstrings and imports):
views.py
def delete_issue(request, issue_id):
return delete_object(request,
model = Issue,
object_id = issue_id,
template_name = 'issues/delete.html',
template_object_name = 'issue')
urls.py
urlpatterns = patterns('issues.views',
(r'(?P<issue_id>\d+)/delete/$', 'delete_issue'),
)
The other generic views (object_list, create_object, etc.) work fine with those parameters. Another problem I have is when using the create_object() function, it says something about a CSRF mechanism, what is that?
You need to provide post_delete_redirect, this means url, where user should be redirected after object is deleted. You can find this in view signature:
def delete_object(request, model, post_delete_redirect, object_id=None,
slug=None, slug_field='slug', template_name=None,
template_loader=loader, extra_context=None, login_required=False,
context_processors=None, template_object_name='object'):