I've used reverse before and it's been fine. But now, I don't know why it's not working. It might be because I'm trying to reverse to a class based view and I've never done that before.
Here's my code -- where am I messing it up?
views.py:
class DocumentRequestDetail(NavMixin, TitleMixin, SelectedBrokerage, DetailView):
model = DocumentRequest
mod_nav = 'brokerage_nav.html'
context_object_name = 'doc'
subtitle = 'Document Request Details'
def MarkDocRequestComplete(request, bpk, pk):
d = DocumentRequest.objects.get(pk= pk)
d.is_complete = True
d.save()
return reverse('doc_request_detail', args=[bpk, pk]) #<--- the offending line
urls.py
from django.conf.urls import include, url
from django.views.generic.list import ListView
from brokerage.views import *
urlpatterns = [
url(r'^(?P<pk>[0-9]+)/detail/$', BrokerageDetail.as_view(), name="brokerage_detail"),
url(r'^(?P<pk>[0-9]+)/edit/$', BrokerageEdit.as_view(), name="brokerage_edit"),
url(r'^(?P<bpk>[0-9]+)/doc-request/all/$', DocumentRequestList.as_view(), name="doc_request_list"),
url(r'^(?P<bpk>[0-9]+)/doc-request/(?P<pk>[0-9]+)/$', DocumentRequestDetail.as_view(), name="doc_request_detail"),
url(r'^(?P<bpk>[0-9]+)/mark-doc-request-complete/(?P<pk>[0-9]+)/$', MarkDocRequestComplete, name="mark_doc_request_complete"),
]
HTML Link that calls MarkDocRequestComplete:
<a href="{% url 'brokerage:mark_doc_request_complete' brokerage.pk doc.pk %}" class='btn btn-lg btn-wide btn-success'>
<i class='ti-check'></i>
Mark Complete
</a>
Error When Clicking HTML Link:
Reverse for 'doc_request_detail' with arguments '(u'1', u'19')' and keyword arguments '{}' not found. 0 pattern(s) tried: []
I don't get it... what am I doing wrong?
Edit I should say that, in the error, the 1 and 19 are the correct values for bpk and pk.
Edit 2 Added full URLs.py
The reason your url tag isn't working, is because you are namespacing it by adding brokerage: to it), when there is no namespace setup in your urls. See the documentation on how to properly setup namespaces.
The correct tag should be:
{% url 'mark_doc_request_complete' bpk=brokerage.pk pk=doc.pk %}
You have to change:
return reverse('doc_request_detail', args=[bpk, pk])
to
return reverse('doc_request_detail', kwargs={'bpk': bpk, 'pk': pk})
You must also change your template tag from:
<a href="{% url 'brokerage:mark_doc_request_complete' brokerage.pk doc.pk %}" class='btn btn-lg btn-wide btn-success'>
to:
<a href="{% url 'brokerage:mark_doc_request_complete' bpk=brokerage.pk pk=doc.pk %}" class='btn btn-lg btn-wide btn-success'>
The reason for these changes is because you have names in your regular expression groups.
Related
I'm running into an issue debugging the following error:
Reverse for 'tasks' with arguments '('',)' not found. 1 pattern(s) tried: ['customer/(?P[-a-zA-Z0-9_]+)/tasks/$']
However, I'm pretty certain that my url parameters are correct and without typos. The url and page worked fine with a function based view, the problem started when I changed to a ListView.
Template:
<a href="{% url 'customerportal:tasks' object.slug %}" class="nav-link">
I also tried:
<a href="{% url 'customerportal:tasks' slug=object.slug %}" class="nav-link">
<a href="{% url 'customerportal:tasks' slug=object.slug|slugify %}" class="nav-link">
DetailView - passing slug param to url
class ProjectDetailView(DetailView):
model = Project
template_name = 'customerportal/customer_portal.html'
def get(self, request, *args, **kwargs):
self.object = self.get_object()
if not self.object.access_verification(request.user):
raise PermissionDenied()
context = self.get_context_data(object=self.object)
return self.render_to_response(context)
My ListView (errors):
class TaskListView(ListView):
model = Task
template_name = 'customerportal/tasks.html'
def get_queryset(self):
self.project = get_object_or_404(Project, slug=self.kwargs['customer_portal'])
return Task.objects.filter(project=self.project.id)
URLs:
path('<slug:slug>/', ProjectDetailView.as_view(), name='customer_portal'),
path('<slug:customer_portal>/tasks/', TaskListView.as_view(), name='tasks'),
I've confirmed that I'm passing the right slug by printing it. The slug parameter is from a parent directory as seen in the urls.py above. I'm guessing ListView doesn't work this way? If not is there a way I could maintain this structure, or do I have to switch back to a function based view in order to get this to work?
Thanks.
there is 2 things to sort out:
your error message says that there is a path that looks similar to this:
path('customer/<slug:customer_portal>/tasks/', TaskListView.as_view(), name='tasks'),
but your paths do not match that pattern of the error message - maybe you edited the paths after the error appeared.
the error type "... arguments '('',)' ..." always means that the parameter in your {% url ... %} statement is empty. In your case that would mean object.slug is empty
Please check what you handover to the template as object.slug
I am working on a project which uses regex urls. The way it is currently designed is you have to manually type the url as a model field which then gets passed to the urls/views as an argument? (I don't fully understand this part yes, still learning). These are the views, urls, and the templates which I think are the issue here. I am trying to automatize the process of adding the slug and that part is working. However, I can't seem to find a way around getting it to work with the way urls are configured currently.
the views sections:
class QuizDetailView(DetailView):
model = Quiz
slug_field = 'url'
template_name = 'exam/quiz_detail.html'
another section of the view where I think the url from the above snippet is turned into a variable which then gets used in url:
class QuizTake(FormView):
form_class = QuestionForm
template_name = 'exam/question.html'
def dispatch(self, request, *args, **kwargs):
self.quiz = get_object_or_404(Quiz, url=self.kwargs['quiz_name'])
if self.quiz.draft and not request.user.has_perm('quiz.change_quiz'):
raise PermissionDenied
The urls:
#passes variable 'quiz_name' to quiz_take view
url(regex=r'^(?P<slug>[\w-]+)/$',
view=QuizDetailView.as_view(),
name='quiz_start_page'),
url(regex=r'^(?P<quiz_name>[\w-]+)/take/$',
view=QuizTake.as_view(),
name='quiz_question'),
and finally the template snippets, this is a detail view of the model/quiz:
<a href="{% url 'quiz_start_page' quiz.url %}">
this one displays the model (which is a quiz users take):
<a href="{% url 'quiz_question' quiz_name=quiz.url %}">
What I have tried so far:
first, since I have the slug field:
class QuizDetailView(DetailView):
model = Quiz
slug_field = 'url' ---this was commented out
template_name = 'exam/quiz_detail.html'
next, I changed the urls from:
url(regex=r'^(?P<slug>[\w-]+)/$',
view=QuizDetailView.as_view(),
name='quiz_start_page'),
url(regex=r'^(?P<quiz_name>[\w-]+)/take/$',
view=QuizTake.as_view(),
name='quiz_question'),
to:
path('<slug:slug>/', QuizDetailView.as_view(), name='quiz_start_page'),
path('<slug:slug>', QuizTake.as_view(), name='quiz_question'),
Then I changed the temlates from:
<a href="{% url 'quiz_start_page' quiz.url %}">
<a href="{% url 'quiz_question' quiz_name=quiz.url %}">
To:
<a href="{% url 'quiz_start_page' quiz.slug %}">
<a href="{% url 'quiz_question' quiz.slug %}">
When I click on the listview for the model/quiz, the url is displayed correctly on browser which I think means the automatic slug is working. However, once I click the link I see this error:
Reverse for 'quiz_question' with keyword arguments '{'quiz_name': ''}' not found. 1 pattern(s) tried: ['(?P<slug>[-a-zA-Z0-9_]+)$']
Really appreciate any help/pointers
Just figured it out myself, I realized I left out the argument which links the Quiz to the TakeQuiz model above.
path('<quiz_name>', QuizTake.as_view(), name='quiz_question'),
Above, instead of the slug I passed the argument <quiz_name> and changed the templates too:
{% url 'quiz_question' quiz_name=quiz.slug %}
That worked.
I'm testing a page.
I'm writing a functional test and I want to click on a link using Selenium 3.141 .
The link is working (if I click on it by myself).
The address should be http://127.0.0.1:8000/lists/addname/ but when selenium click on it go to http://localhost:63286/lists/addname/lists/addname/ and ofcourse it doesn't find the page (63286 is a number always different but shouldn't be the problem, if I click on the link before it does (using time.sleep, for example) I go to the page http://localhost:63286/lists/addname and it works).
I'm not expert so maybe it's a trivial error and I don't know what code can be relevant, so tell me if you have to know more.
Edit: probabily is something related to load time /Edit
My functional_tests.py:
class NewVisitorTest(LiveServerTestCase):
def setUp(self):
self.browser = webdriver.Firefox()
def tearDown(self):
self.browser.quit()
def test_can_add_name_and_read_it_after(self):
# Bob go to the homepage
self.browser.get(self.live_server_url)
# He notice the title in header is Home
self.assertIn('Home', self.browser.title)
# He finds and clicks the link on the sidebar for the addname page
element = self.browser.find_element_by_link_text('Add Name')
# element = self.browser.find_element_by_xpath('/html/body/div/div[1]/nav/div/ul/li[2]/a') # this gives the same problem
time.sleep(1)
element.click()
In my template.html the link appear two time but that shouldn't be the problem:
<div class="navbar">
<a class="nav-link" href="{% url 'lists:addname' %}">{% trans "Add Name" %}</a>
</div>
[...]
<div class="sidebar">
<a class="nav-link" href="{% url 'lists:addname' %}">{% trans "Add Name" %}</a>
</div>
My main url.py:
urlpatterns = [
path('lists/', include('lists.urls')),
]
and my lists url.py:
urlpatterns = [
path('addname/', views.addname, name='addname'),
]
My views.py:
def addname(request):
if request.method == 'POST':
Item.objects.create(text=request.POST['item_text'])
return redirect('lists/addname/')
items = Item.objects.all()
return render(request, 'addname.html', {'items': items})
Thank you!
I have a html template on which multiple messages are posted and can be deleted using a 'delete' button that has been created. My code seeks to search for the id of the item to be deleted and delete it, redirecting to /deleteMessage and concatenating with the id number. I don't fully understand the process and have an error I cannot spot.
html form
<ul>
{% for g in all_items %}
<li> {{ g.content }}
<form action="/deleteMessage/{{g.id}}/"
style="display: inline;"
method="post">{% csrf_token %}
<input type="submit" value="Delete"/>
</form>
</li>
{% endfor %}
</ul>
views.py relevant code
def deleteMessage(request,GuestBookItem_id):
item_to_delete =GuestBookItem.objects.get(id=GuestBookItem_id)
item_to_delete.delete()
return HttpResponseRedirect('/worldguestbook/')
urls.py
urlpatterns = [
path('admin/', admin.site.urls),
path('worldguestbook/',worldguestbookView),
path('login/',loginView),
path('addMessage/',addMessage),
path('deleteMessage/',deleteMessage),
]
I imagine it is this line that is causing the error - an error in concatenation and not redirecting to the right path.
**<form action="/deleteMessage/{{g.id}}/"**
Error message:
Page not found (404)
Request Method: POST
Request URL: http://127.0.0.1:8000/deleteMessage/17/
Using the URLconf defined in mysite.urls, Django tried these URL patterns, in this order:
admin/
worldguestbook/
login/
addMessage/
deleteMessage/
The current path, deleteMessage/17/, didn't match any of these.
What I tried:
I tried, in views.py changing this to g.id (instead of GuestBookItems.id) to match with what is in the form, but that didn't work either.
item_to_delete =GuestBookItem.objects.get(id=g_id)
You need to capture GuestBookItem_id in the URL pattern:
path('deleteMessage/<int:GuestBookItem_id>/', deleteMessage),
Note that in Python, you would normally use guest_book_item_id as the variable name. Or since it's the primary key of a model instance, you could use pk. It would be a good idea to use get_object_or_404, so that you get a 404 page when the item does not exist.
You're already using a POST request, which is a good idea when you are changing or deleting objects. You should also check that it's a POST request in the view.
Finally, it's a good idea to reverse URLs instead of hardcoding them. First, you need to add names to your URL patterns, then you can use {% url %} in the template and reverse() or the redirect shortcut in the template.
Putting that together, you get:
<form action="{% url 'delete_message' g.id %}">
urlpatterns = [
path('admin/', admin.site.urls),
path('worldguestbook/', worldguestbookView, name="worldguestbook"),
path('login/', loginView, name="login"),
path('addMessage/', addMessage, name="add_message"),
path('deleteMessage/', deleteMessage, name="delete_message"),
]
path('deleteMessage/<int:pk>/', deleteMessage),
from django.shortcuts import get_object_or_404, redirect
def deleteMessage(request, pk):
if request.method == "POST"
item_to_delete = get_object_or_404(GuestBookItem, pk=pk)
item_to_delete.delete()
return redirect('worldguestbook')
I have an issue with my web-app django.
In example, user can add an artist, and with this artist, he can (list, delete, play) music.
When the user click on the artist, the URL is 'music/1/' where the artist ID is 1, and music is listed.
When user want delete a music, the URL is 'delmusic/1/' where the music ID is 1.
delmusic function works, but returns an error PageNotFound with this http URL :
'http://host.local/appli/delmusic/1/webgui.views.music'
My urls.py :
url(r'^music/(\d+)/$', 'webgui.views.music'),
url(r'^delmusic/(\d+)/$','webgui.views.delmusic'),
My music template :
<a href="{% url 'webgui.views.delmusic' music.id %}"style="margin-bottom: 3px" type="button">
My view :
def music(request, id):
listmusic = Music.objects.filter(artist=id)
return render(request, 'music.html', {'listmusic': listmusic})
def delmusic(request, id):
music = Music.objects.get(id=id)
music.delete()
return redirect('webgui.views.music')
I think there is confusion with music.id and arist.id, but I don't know..
Maybe you will have an idea ?
You have a slight issue with your urls.py - the 2nd argument points to the views function, but is not used as a reference in the templates, for that you need to do:
url(r'^music/(\d+)/$', 'webgui.views.music', name='music'),
url(r'^delmusic/(\d+)/$','webgui.views.delmusic', name='delmusic'),
and then in the template
<a href="{% url 'delmusic' music.id %}" style="margin-bottom: 3px" type="button">
or if you had a namespace defined for your app in django_settings/urls.py:
<a href="{% url '<APPNAMESPACE>:delmusic' music.id %}" style="margin-bottom: 3px" type="button">
and then at then in views.py do
from django.core.urlresolvers import reverse
def delmusic(request, id):
music = Music.objects.get(id=id)
artist_id = music.artist.id
music.delete()
return redirect(reverse('music', args=[artist_id]))