Django reverse url found with arguments but fails with keywords - python

This is yet another question regarding the error:
Reverse for 'dataPoints' with arguments '()' and keyword arguments '{u'loadID': 5}' not found. 1 pattern(s) tried: [u'loads/dataPoints/']
I've sifted through scads of related post but can't seem to figure out what's going on. The problem is this: in an app using url namespaces, a view template fails with the above error when I try to pass keyword arguments to the url, but works if I use position arguments.
This is what is giving me the above error:
Top-level urls.py:
urlpatterns = patterns('',
url(r'^admin/', include(admin.site.urls)),
...
url(r'^loads/', include(sig.views.data_loads.urls_data_loads, namespace="loads")),
url(r'^authentication/', include(sig.views.authentication.urls_authentication, namespace="authentication")),
url(r'^account/', include(sig.views.account.urls_account, namespace="account")),
)
urls.py for "loads":
urlpatterns = patterns('',
url(r'^dataPoints', views.DataPoints.as_view(), name='dataPoints')
)
template.html:
points
Then it says it can't find the reverse. Based on some of the related threads I've found, I've tried:
- trying the link without quotes, i.e. {% url loads:dataPoints ... %} (it fails)
- tried different regex patterns, e.g. url(r'^dataPoints(.)*) (still can't find reverse)
I can easily work around this by using positional arguments but it's really bugging me that I can't figure it out. I've used keyword args like this in apps before, and I'm wondering if something is screwy because I'm using url namespaces? Either that or, more likely, I'm doing something completely boneheaded.
EDIT: Adding code for DataPoints view:
class DataPoints(TemplateView):
template_name = "data_loads/templates/dataPoints.html"
def get(self, request):
loadID = request.GET["loadID"]
return self.render_to_response({})

urlpatterns = patterns('',
url(r'^dataPoints', views.DataPoints.as_view(), name='dataPoints')
)
Your modified url does not take any parameter as the one before takes loadID.
So the behavior you are seeing is correct.
To use kwargs, keep your url same and use the template as you are doing
points

I'm taking your comments on Rohans answer into account.
The pattern r'^dataPoints' will match any url that starts 'dataPoints', including dataPoints?load=5, but 'load' will be added to request.GET (so request.GET['load'] is '5'). This is the reason you have never seen anyone doing something like r'^dataPoints?loadID=[0-9]+$ as it is not how url patterns work. Rohans original answer here is correct, you only need to revert to the orginal pattern in urls.py for 'load'. You should try what he has suggested and accept his answer if the error goes away, which I'm sure it will.

OK - I knew it had to be something dumb on my part. I assumed that "keyword arguments" in the context of url dispatching meant GET parameters, not keyword args routed to the get() method. This is also why I was so confused by the comments mentioning a method signature. Ugh. Pretty dumb but hopefully this will help anyone else who makes the same mistake. Anyway, the final answer is that the line in my template file should have read:
points
The post that finally caused this to click in my head was this one. Thanks, everyone, for your help.

Related

Django: Passing parameters in URL as query arguments

How can I pass parameters via URL as query parameters to avoid multiple and complicated url patterns?
For example, instead of making a complicated url like
example.com/page/12/red/dog/japan/spot
or something like that, and then a corresponding entry in urls.py that will parse that url and direct it to a view, I want to simply get a url where I can freely add or remove parameters as needed similar to the ugly way
example.com/page?id=12&color=red&animal=dog&country=Japan&name=spot
Then in urls.py simply have something like
path('page/<parameter_dictionary>', views.page, name='page' parameters='parameter_dictionary)
If I have to use url patterns, how can I account for urls that have parameters that may or may not fit the pattern, such as sometimes
"/page/12/red/dog/Japan/spot" -> path('page/<int:id>/<str:color>/<str:animal>/<str:country>/<str:name>', views.page, name='page'),
"/page/12/dog/red/Japan/"-> path('page/<int:id>/<str:animal>/<str:color>/<str:country>', views.page, name='page')
"/page/dog/red/Japan/"-> path('page/<str:animal>/<str:color>/<str:country>', views.page, name='page')
I would like to just have anything sent to http://example.com/page/
go to views.page(), and then be accessible by something like
animal = request.GET['animal']
color = request.GET['color']
id = request.GET['id']
etc. so examples below would all work via one entry in urls.py
example.com/page?id=12&animal=dog&country=Japan&name=spot
example.com/page?id=12&color=red&animal=dog&name=spot
example.com/page?id=12&country=Japan&color=red&animal=dog&name=spot
You are looking for queryparameters and you are almost done with it. The following code is untested but should kinda work:
def page(request):
animal = request.GET.get("animal",None) # default None if not present
color = request.GET.get("color",None)
return render(request,'some_html.html')
# urls.py:
path('page/', views.page, name='page')
You access the queryparameters via the passed request object request.GET. This is a dict like object. The main difference is that this object handles multi keys.
For example if you pass the these params ?a=1&a=2 to your url, it converts request.GET.getlist("a") # Returns ["1","2"] to a list.
request.GET.get("a") returns the last passed value "2" as #Kbeen mentioned in comments,. Read more about QueryDict here.
Also be sure to know the difference and best practice for url parameters and queryparameters. Example Stackoverflow post
Edit: Added request.GET.getlist()

re_path syntax in *application* urls.py

I have been getting this error for almost a week. I have googled and checked the docs and looked for youtube videos. I cannot find an answer to this seemingly simple and obvious question: What is the syntax for re_path() in the included urls from my apps?
error:
Reverse for 'jhp_url' with keyword arguments '{'slug': ''}' not found. 1 pattern(s)
tried: ['(?P<twodigit>[a-z]{2,3})/courts/(?P<slug>[-a-zA-Z0-9_]+)/$']
That pattern is correct! So obviously, the problem is slug has an empty string. But why? I have it in reverse():
def get_absolute_url(self):
return reverse('jhp_url', kwargs={'slug': self.slug})
Q1:Why isn't it seeing the kwarg from reverse() and using self.slug?
If I try to put self.slug in the view or the url as extra arguments, PyCharm complains.
Putting the namespace in reverse() and the template makes absolutely no difference! I get the same error.
BUT, if I take the namespace out of those two(1) places, I get a different error:
Reverse for 'jhp_url' not found. 'jhp_url' is not a valid view function or pattern name.
(1) as opposed to having it in one but not the other
So it seems like the first error I mentioned here is closer to being right.
My debug_toolbar template context says:
'slug': '^(?P<slug>[-a-zA-Z0-9_]+)/$'
I'm pretty sure that's wrong. It should be the actual slug and not the pattern. That's why I have focused on the app urls.py. But, as I said at the top of this rant. I have not been able to find anything on the syntax of re_path() in the included app urls!
bench.urls.py:
urlpatterns = [
re_path(r"^$", twodigit_testt1, {'slug': r"^(?P<slug>[-a-zA-Z0-9_]+)/$"},
name='tdr'),
re_path(r"(?P<slug>[-a-zA-Z0-9_]+)/$", courtdetail, name='jhp_url'),
Of course I still get these errors, but my point here is that the interpreter runs with that. But when I try things like
re_path(r"^$", twodigit_testt1, {'slug': r'^(?P=slug)/$'}, name='tdr'),
I just get syntax errors.
Finally, please note that these errors are coming because the list template that twodigit_test1 is calling has urls to the individual detail pages in it. If I take the detail urls out of the template, it works. But if I go directly to the detail page, after importing my app views into the project urls, that works, too! It's only the list template + detail urls combination that is the problem - and if you can't list your details on your list page, what's the point? I have tried both the url template tag and get_absolute_url in the template. Finally, I did ask an earlier version of this question. I know some people don't like that but it did not resolve this issue. I have reworked and refocused the question so it is not identical. Plus, I wasn't using re_path() then.

Django 2.1 - What does namespace= do on an include in urls.py

I pretty much have app_name and namespaces working well, but I have a simple clarification - and I think this might be something that is in my 2.1 Django that might have been different in earlier Django versions.
I have an app named route and in its urls.py I have:
app_name = 'route'
urlpatterns = [
path('first', views.FirstView.as_view(), name='first-view'),
]
In my views.py and template files I use route:first-view in my reverse() calls and {% url .. %} calls and it all works.
My confusion is in my project wide urls.py where I say something like:
urlpatterns = [
path('route/', include('route.urls', namespace='route')),
]
The part that is making me crazy is that it appears that the namespace= parameter does absolutely nothing. My code works the same if I leave it out or even if I say namespace='abc' - it seems to be 100% ignored by Django 2.1.
Also if I use namespace='route' without app_name being set, I get an error: Specifying a namespace in include() without providing an app_name is not supported.
If namespace= is ignored - then I am happy just setting app_name - I will leave it off - It just seems like it must have a purpose that I just can't figure out. Or maybe this is something unnecessary and from an earlier version of Django.
Note: I have looked at a similar question and answer but that example does not explain how namespace works when using path. I try to avoid the url/regular expression pattern and use the simpler path pattern as much as possible.
Using namespace in the include() allows you to include the same app more than once, with a different namespace for each instance.
You can see an example in the docs, where the polls app is included twice with two different namespaces.
If you only include route.urls once in your project, then the namespace='route' isn't required, and can be removed.
With namespace, you can do this in your template:
Change pass
If you have an other url with the same name "changepass" in an other app, you can do the same changing only the namespace:
Change pass
i hope it will help ^^

Django namespaced URLs and parameters

I'm encountering an odd problem with namespaced url in Django, and I cannot find what I am doing wrong while it is working on simpler examples and using the
Basically, my project is made of two apps, user and model. In my general urls.py, I defined :
url(r'^model/', include('model.urls', namespace="model")),
url(r'^user/', include('user.urls', namespace="user")),
In the user.urls.py file, I defined the following url:
url(r'^duo/(?P<pseudo>[a-z]+)/$',views.duo, name='duo'),
The duo view is rather simple :
def duo(request,pseudo):
print pseudo
return render(request,"user/duo.html",locals())
Therefore, when I use in my templates:
{% url 'user:duo' lena %}
I expect the url to be resolved as /user/duo/lena. Instead, I got the following NoReverseMatch:
Reverse for 'duo' with arguments '('',)' and keyword arguments '{}' not found. 1 pattern(s) tried: [u'user/duo/(?P<pseudo>[a-z]+)/$']
I take any guess to fix my mistake !
Ok, Pynchia and Bernhard comments help me to fix my bug ! Now, I am using
"{% url 'user:duo' "lena" %}"
in my template and it's running smoothly ! Many thanks to you !
Edited according to the dicussion:
You need to quote your paramater. Also keyword parameters might make things clearer:
{% url 'user:duo' pseudo='lena' %}
If you don't quote the value, Django assumes this is a context variable and as lena is not a context variable in your case this evaluates to None. The error actually tells you, you didn't provide args or kwargs for the reverse lookup.

How do I use django.core.urlresolvers.reverse with a function reference instead of a named URL pattern?

In my urls.py file, I have:
from myapp import views
...
(r'^categories/$', views.categories)
Where categories is a view function inside myapp/views.py. No other URLconf lines reference views.categories.
In a unit test file, I’m trying to grab this URL using django.core.urlresolvers.reverse(), instead of just copying '/categories/' (DRY and all that). So, I have:
from django.core.urlresolvers import reverse
from myapp import views
...
url = reverse(views.categories)
When I run my tests, I get a NoReverseMatch error:
NoReverseMatch: Reverse for '<function categories at 0x1082f30>' with arguments '()' and keyword arguments '{}' not found.
It matches just fine if I make the URL pattern a named pattern, like this:
url(r'^categories/$', views.categories, 'myapp-categories')
And use the pattern name to match it:
url = reverse('myapp-categories')
But as far as I can tell from the reverse documentation, I shouldn’t need to make it a named URL pattern just to use reverse.
Any ideas what I’m doing wrong?
Jack M.'s example is nearly correct.
It needs to be a url function, not a tuple, if you want to use named urls.
url(r'^no_monkeys/$', 'views.noMonkeys', {}, "no-monkeys"),
After futher investigation, turns out it was an issue with how I was importing the views module:
How do I successfully pass a function reference to Django’s reverse() function?
Thanks for the help though, guys: you inspired me to look at it properly.
This does work, and all the code that you've pasted is correct and works fine (I just copied it into a clean test/project app and it reversed the URL without any problem). So there's something else going on here that you haven't showed us. Simplify down to the bare-bones basics until it works, then start adding complexity back in and see where it's breaking.
Also, you can do "./manage.py shell" and then interactively import the reverse function and your view function and try the reverse. That'll remove the test setup as a possible cause.
The reverse function actually uses the "name" of the URL. This is defined like so:
urlpatterns = patterns('',
(r'^no_monkeys/$', 'views.noMonkeys', {}, "no-monkeys"),
(r'^admin/(.*)', admin.site.root),
)
Now you would call reverse with the string "no-monkeys" to get the correct url.
Ninja Edit: Here is a link to the django docs on the subject.

Categories