NoReverseMatch: with arguments '()' and keyword arguments - django

I am using Django 1.5 and trying to pass args to my URL. When I use the first two args then the below code works fine, with the third args I am getting an error. I have already referred to the new Django 1.5 update for url usage and accordingly used quotes for the URL name.
NoReverseMatch: Reverse for 'add_trip' with arguments '()' and keyword arguments '{u'city': 537, u'score': 537, u'time': 35703, u'distance': 1196.61}' not found
urls.py
url(
r'^add/(?P<city>\w+)/(?P<score>\w+)/(?P<distance>\w+)/(?P<time>\w+)$',
'trips.views.add_trip',
name='add_trip'
),
html file
Add/delete
If I use only two args (i.e city and score, then it works fine) else I get the no reverse match error.
views.py
def SearchTrips(request):
city = request.POST['city'].replace(" ","%20")
location = request.POST['location'].replace(" ","%20")
duration = request.POST['duration']
#url = "http://blankket-mk8te7kbzv.elasticbeanstalk.com/getroutes?city=%s&location=%s&duration=%s" % (city, location, duration)
url= "http://blankket-mk8te7kbzv.elasticbeanstalk.com/getroutes?city=New%20York%20City&location=Park%20Avenue&duration=10"
print url
try:
resp = urllib2.urlopen(url)
except:
resp = None
if resp:
datas = json.load(resp)
else:
datas = None
return render(request, 'searchtrips.html', {'datas': datas})

The distance value 1196.61 does not match the regex because of the decimal point.
You can use
(?P<distance>[\w\.]+)
which matches uppercase A-Z, lowercase a-z, digits 0-9, hyphens and decimal points.
Alternatively, you could use
(?P<distance>[\d\.]+)
Which only matches digits 0-9 and decimal points.

Related

Django unquote() with url parameters

I had used unquote in my urls before to get special characters in the url like so:
path('example/<str:phone_number>', views.find_user_by_phone_number.as_view(), name='api.find_user_by_phone_number'),
#call with example/+849323212231
and in my views:
from urllib.parse import unquote
.....
phone_number = unquote(phone_number)
print(phone_number)
It worked great and i got +849323212231 with special character +
But now i need to make url with multiple parameters that can has phone_number in it:
path('example', views.find_user_by_phone_number.as_view(), name='api.find_user_by_phone_number'),
#call with example?phone_number=+849323212231
With view to handle parameter:
...
phone_number = unquote(request.GET.get('phone_number'))
print(phone_number)
And the result from the print i got was " 849323212231" with whitespace at the start.
Seems like value from request.GET.get('phone_number') return " 849323212231" so plus turned into whitespace.
Expected to get +849323212231 from request.GET.get('phone_number')
How do i get special character with named parameter in url ?

How to use redirect with multiple parameters in Django views?

I am trying to redirect to a function from another function in views.
But I am getting following error
NoReverseMatch at /sigma/status1/
Reverse for 'testview' with keyword arguments '{'amount': 1.000, 'stat':'Approved', 'ref': '10917'}' not found. 1 pattern(s) tried: ['sigma\\/status2/(?P<amount>\\d+)/(?P<stat>[a-z][A-Z]+)/(?P<ref>\\d+)/$']
Below is corresponding part of my views.py
return redirect(reverse('testview',kwargs={'amount':1.000,'stat':'Approved','ref':str(res['ref'])}))
def payment_status2(request,amount,stat,ref):
return render(request, 'confirm1.html')
Below is corresponding part of my urls.py
urlpatterns = [
url('status1/', views.payment_status1),
url(r'^status2/(?P<amount>\d+)/(?P<stat>[a-z][A-Z]+)/(?P<ref>\d+)/$', views.payment_status2,name="testview"),
]
Your stat regex is incorrect:
?P<stat>[a-z][A-Z]+
This indicates that the argument should start with a lowercase letter and then followed by one or more uppercase letters (such as aPPROVED). You should change it to:
?P<stat>[a-zA-Z]+
or
?P<stat>\w+

Translate ?page_no=5 to <QueryDict: {'page_no': ['5']}>

When I send a query request like ?page_no=5 from the brower:
http://127.0.0.1:8001/article/list/1?page_no=5
I get the output in the debugging terminal
def article_list(request, block_id):
print(request.GET)
<QueryDict: {'page_no': ['5']}>
Django encapsulates the page_no=5 to a dict {'page_no': ['5']}
How Django accomplish such a task, are the regex or str.split employed?
Short answer: we can inspect the source code to see how the QueryDict is constructed. It is done with a combination of regex splitting and unquoting.
This can be done by using the constructor. Ineed, if we call:
>>> QueryDict('page_no=5')
<QueryDict: {u'page_no': [u'5']}>
The constructor uses the limited_parse_qsl helper function. If we look at the source code [src]:
def __init__(self, query_string=None, mutable=False, encoding=None):
super().__init__()
self.encoding = encoding or settings.DEFAULT_CHARSET
query_string = query_string or ''
parse_qsl_kwargs = {
'keep_blank_values': True,
'fields_limit': settings.DATA_UPLOAD_MAX_NUMBER_FIELDS,
'encoding': self.encoding,
}
if isinstance(query_string, bytes):
# query_string normally contains URL-encoded data, a subset of ASCII.
try:
query_string = query_string.decode(self.encoding)
except UnicodeDecodeError:
# ... but some user agents are misbehaving :-(
query_string = query_string.decode('iso-8859-1')
for key, value in limited_parse_qsl(query_string, **parse_qsl_kwargs):
self.appendlist(key, value)
self._mutable = mutable
If we look at the source code of limited_parse_qsl [src], we see that this parser uses a combination of splitting, and decoding:
FIELDS_MATCH = re.compile('[&;]')
# ...
def limited_parse_qsl(qs, keep_blank_values=False, encoding='utf-8',
errors='replace', fields_limit=None):
"""
Return a list of key/value tuples parsed from query string.
Copied from urlparse with an additional "fields_limit" argument.
Copyright (C) 2013 Python Software Foundation (see LICENSE.python).
Arguments:
qs: percent-encoded query string to be parsed
keep_blank_values: flag indicating whether blank values in
percent-encoded queries should be treated as blank strings. A
true value indicates that blanks should be retained as blank
strings. The default false value indicates that blank values
are to be ignored and treated as if they were not included.
encoding and errors: specify how to decode percent-encoded sequences
into Unicode characters, as accepted by the bytes.decode() method.
fields_limit: maximum number of fields parsed or an exception
is raised. None means no limit and is the default.
"""
if fields_limit:
pairs = FIELDS_MATCH.split(qs, fields_limit)
if len(pairs) > fields_limit:
raise TooManyFieldsSent(
'The number of GET/POST parameters exceeded '
'settings.DATA_UPLOAD_MAX_NUMBER_FIELDS.'
)
else:
pairs = FIELDS_MATCH.split(qs)
r = []
for name_value in pairs:
if not name_value:
continue
nv = name_value.split('=', 1)
if len(nv) != 2:
# Handle case of a control-name with no equal sign
if keep_blank_values:
nv.append('')
else:
continue
if nv[1] or keep_blank_values:
name = nv[0].replace('+', ' ')
name = unquote(name, encoding=encoding, errors=errors)
value = nv[1].replace('+', ' ')
value = unquote(value, encoding=encoding, errors=errors)
r.append((name, value))
return r
So it splits with the regex [&;], and uses unquote to decode the elements in the key-value encoding.
For the unquote(..) function, the urllib is used.

Unable to Fix Django NoReverseMatch Error

I'm getting a NoReverseMatch error when I try to pass two arguments from one view to another. Here is the view that is passing the arguments:
# promotion/views.py
def enter_promo_code(request, template):
if request.method == "POST":
form = PromotionCodeForm(request.POST)
if form.is_valid():
message_text, expiry_date = process_valid_promo_code(request.user, form.cleaned_data['promo_code'])
return HttpResponseRedirect(reverse('welcome-page-promo', \
kwargs={'message_text': message_text, 'expiry_date': expiry_date}))
else:
form = PromotionCodeForm(label_suffix="")
context = {'form': form}
return render(request, template, context)
Here is the receiving view. Note that the two input arguments are optional. The urlpatterns show that this view can be called with or without arguments.
# home/views.py
def welcome_page(request, template, message_text=None, expiry_date=None):
account = Account.objects.get(pk=request.user.id)
context = {'uid': request.user.id, 'account_type': account.type.account_type_cd, 'message_text': message_text, 'expiry_date': expiry_date}
return render(request, template, context)
Here are the urlpatterns for the receiving view:
# home/urls.py
url(r'^welcome/$',
'home.views.welcome_page',
{'template': 'welcome_page.html'},
name='welcome-page'),
url(r'^welcome/(?P<message_text>\w{1,})/(?P<expiry_date>\w{1,})/$',
'home.views.welcome_page',
{'template': 'welcome_page.html'},
name='welcome-page-promo'),
When I execute the promotion view, I get this error when the return HttpResponseRedirect command executes:
NoReverseMatch at /promotion/code/
Reverse for 'welcome-page-promo' with arguments '()' and keyword arguments '{'message_text': u'Your promotion code was approved! You will receive a one-year free trial membership which expires on ', 'expiry_date': 'Jul. 18, 2018'}' not found. 1 pattern(s) tried: ['welcome/(?P<message_text>\\w{1,})/(?P<expiry_date>\\w{1,})/$']
I'm running this same code pattern in a different application in the project and it runs without error. Can anyone see what I'm doing wrong?
You have two problems here, one of design and one of implementation.
The design problem is that you probably shouldn't have such long text in your URLs. I believe Django will handle the argument escaping for you, but it's still not going to be the easiest pattern to work with. It looks to me like your message_text argument is likely to be static, or at least selected from a small number of possibilities. Most likely you should record it in your template, create a model for it and pass around the ID, or something along those lines. There's nothing wrong with passing dates around in a URI, although I prefer a simpler format like 2018-07-18 over Jul. 18, 2018, but if it's truly an expiration date you probably want to have a model for memberships and set it as an attribute there, then look it up it your welcome page view.
Putting that aside and looking at your implementation problem - your view regexps only match one or more characters from the \w class, which is defined as:
When the LOCALE and UNICODE flags are not specified, matches any alphanumeric character and the underscore; this is equivalent to the set [a-zA-Z0-9_]. With LOCALE, it will match the set [0-9_] plus whatever characters are defined as alphanumeric for the current locale. If UNICODE is set, this will match the characters [0-9_] plus whatever is classified as alphanumeric in the Unicode character properties database.
However, your args include characters like ! and spaces. Use a regexp that matches your desired arguments - [^/]+ is one, if you want to be forgiving. (+ is more readable than {1,} in my opinion, but they mean the same thing.)

(django URLconf) page not found error only for urls with '-' character

I have a weird problem can't figure out whats wrong, I get 404 errors for any url that contains a '-' character...
my urls.py in the project root works fine
url(r'^serialy/', include('movieSite.series.urls')),
next, is
urlpatterns = patterns('',
url(r'^$', views.serialy_index, name='serialy_index'), #this works
(r'^(?P<serial_title>[\w]+)/$', serial),
)
The second one, using serial_title, works only if the series' title is something like, 'Dexter,' or 'Continuum.' But other series have titles like 'Family guy,' so when I create the url I use a function that changes it to 'Family-guy,' but for some reason it won't work for those titles with the '-' characters. I always get a 404 error like this
Using the URLconf defined in movieSite.urls, Django tried these URL patterns, in this order:
^serialy/ ^$ [name='serialy_index']
^serialy/ ^(?P<serial_title>[\w]+)/$
^static\/(?P<path>.*)$
The current URL, serialy/Whats-with-Andy/, didn't match any of these.
so here the url serialy/whats-with-andy/ doesn't match, but if I visit serialy/continuum it works fine?? anyone have any ideas as to what could cause this?
Oh and this is what the view looks like
def strip(s):
s.replace('-',' ')
return s
def serial(request, serial_title=None) :
s_title = strip(serial_title)
obj = Show.objects.get(title__icontains=s_title)
#episodes = obj.episodes
des = obj.description
img = obj.image
title = obj.title
t = get_template('serial.html')
html = t.render(Context({
'the_title':title,'the_image':img,'the_description':des
}))
return HttpResponse(html)
The regex [\w]+ only matches words and not special chars like -.
If you change it to [-\w]+ it'll match "slug" urls.
I think your regex is failing because '-' is not considered a match for \w. See here:
https://docs.python.org/2/library/re.html