I have created a Dynamic Url with optional parameter
e.g., If my url is as www.example.com/getTest/1/
Now this 1 in url is optional , to handle this in views I have used None like
def function(request, id=None):
pass
Thus if there is no id in URL then still the function works for me.
But I am facing issue while testing this in unit cases.
if I use url as url = reverse('yescourse:academypage_url', args=[None]) it gives me the error
NoReverseMatch: Reverse for 'academypage_url' with arguments '('new', None)' and keyword arguments '{}' not found.
So Please Tell me how I can handle these optional url in Test cases or in Reverse.
Edit :
url(r'^getTest/(?P<action>\w+)/(?P<id>\d*)$', 'app.views.create_edit_academypage', name='academypage_url'),
You made the view function's id parameter optional, but it's not optional in the url pattern. You firsty need to rewrite your pattern as :
r'^getTest/(?P<action>\w+)/(?P<id>\d+)?$'
=> the whole 'id' sub-pattern is optional, but if it's not it must match one or more numerics.
Once done, you can reverse the url by not passing any of the args nor kwargs arguments:
url = reverse('yescourse:academypage_url')
or by passing an empty list
url = reverse('yescourse:academypage_url', args=[])
or by passing None
url = reverse('yescourse:academypage_url', args=None)
but not by passing a list containing None.
Related
Attempting to regex match a string like so:
'1,2'
Using Django rest framework url method to parse incoming string, I tried this:
url(r'^path/to/api/end_point/(?P<player_ids>"\'1,2\'")/',
PlayerResultsView.as_view(),
name='get_players)
The error I get:
django.core.urlresolvers.NoReverseMatch: Reverse for 'get_players'
with arguments '()' and keyword arguments '{'player_ids': '1,2'}' not
found. 1 pattern(s) tried:
['path/to/api/end_point/(?P<player_ids>"\'1,2\'")/']
Overall Goal: pass comma separated string ('1,2,3,4') to REST endpoint, split on the comma and continue processing.
Solution 1
What you are trying to do is match a fixed string 1,2. If you want a variable input whether it is 1,2 or 1,2,3,4 or others, then try this regex pattern [\d,]+ which will capture non-empty string containing any numbers and commas.
re_path(r'^path/to/api/end_point/(?P<player_ids>[\d,]+)/', views.some_view),
Sample URL would be:
http://127.0.0.1:8000/path/to/api/end_point/1,2,3,4/
Solution 2
Instead of such variable input in the path, you might be interested in making it query parameters instead. So something like:
path('path/to/api/end_point/', views.some_view),
Sample URL would be:
http://127.0.0.1:8000/path/to/api/end_point/?player_ids=1,2,3,4
Then, just access it as part of the request.GET or request.query_params (if using djangorestframework) in your view.
def some_view(request, **kwargs):
print(f"{request.GET.get('player_ids')=}")
print(f"{request.query_params.get('player_ids')=}")
Output
request.GET.get('player_ids')='1,2,3,4'
request.query_params.get('player_ids')='1,2,3,4'
[08/Sep/2021 01:44:05] "GET path/to/api/end_point/?player_ids=1,2,3,4 HTTP/1.1" 200 17
I decided to go with a POST, easier to pass more complex parameters.
My URL pattern:
url(r'^path/to/api/end_point/',
PlayerResultsView.as_view(),
name='get_players)
My POST data is an array of player ids:
list_of_search_ids = [player1.player_id, player2.player_id]
data = {'player_ids': list_of_search_ids}
url = reverse(
"get_players"
)
resp = self.client.post(url, json.dumps(data), content_type='application/json')
Good day everyone,
I am having a really strange issue with Flask's RequestParser.parse_args(). Below is a snippet of my __init__ method of the relevant class:
def __init__(self, arg1, arg2):
self.arg1 = arg1
self.arg2 = arg2
self.arg_parser = reqparse.RequestParser()
self.arg_parser.add_argument('optional_arg_from_url', type=bool, default=False)
Notice I only add 1 argument to self.arg_parser. Then, in the post method, I want to retrieve optional_arg_from_url with arg_parser.parse_args() as follows:
def post(self):
# Authorization in headers
token = request.headers.get('Authorization').split()[1]
# Parse args
args = self.arg_parser.parse_args()
optional_arg_from_url = args['optional_arg_from_url']
Now, an example of the request url containing the optional arg would look as follows:
http://localhost:8080/path/to/endpoint/?optional_arg_from_url=True
The error that I am getting is ValueError: not enough values to unpack: expected 2, which is raised when args = self.arg_parser.parse_args() is called. I don't understand why 2 values are expected, since I only add one argument to the parser. Also, why would a value error be raised when I try to parse the args? Shouldn't it just parse all the args regardless?
Another interesting thing, is that the corresponding unit tests are working, regardless of whether the optional arg is included in the url or not. The code ALSO works if I do not include the optional arg in the url (which means the arg defaults to False) and gets parsed correspondingly. It is just when I try to overwrite the arg's value to True within the request url when a value error is raised.
I also made sure that optional_arg_from_url is spelled exactly the same everywhere, so that is not the issue.
Any assistance is appreciated.
I'm trying to inspect a request's argument before the get() is invoked. I have a route which is described as so:
user_route = r"/users/key=(?P<key>\w+)"
app = web.Application([
web.URLSpec(user_route, user_manager.UserHandler), ..])
Next, (in the handler) prepare() is used to inspect the request before get().
def prepare(self):
# inspect request arguments
print(self.request.arguments) # prints "{}"
The problem I'm having is that I cannot access the arguments from prepare(). The last statement prints an empty dict. My get() successfully uses the arguments as they are passed in the function like this:
def get(self, key):
print(key) #works
How do I access arguments in prepare()? I have also tried self.argument('key') which gives an error "400 GET .... Missing argument key", but requested URL does have a key argument in it.
In your code key is not a GET-argument, it's a part of a path. tornado.we.URLSpec passes any capturing groups in the regex into the handler’s get/post/etc methods as arguments.
tornado.web.RequestHandler has RequestHandler.path_args and RequestHandler.path_kwargs which contain the positional and keyword arguments from URLSpec. Those are available in prepare method:
def prepare(self):
# inspect request arguments
print(self.path_kwargs) # prints {"key": "something"}
As Gennady Kandaurov mentioned, you passed the key as a part of the we.URLSpec path and you can access it using Tornado's self.path_kwargs. If you wanted to pass it as an argument you could used RequestHandler.get_argument to get the argument on your get method and use self.request.arguments on your prepare method to access it as your initial intention.
Your code could be as follow:
class Application(tornado.web.Application):
def __init__(self):
user_route = r"/users"
app = tornado.web.Application([
tornado.web.url(user_route, user_manager.UserHandler), ..])
class UserHandler(tornado.web.RequestHandler):
def get(self):
key = self.get_argument('key')
print(key)
def prepare(self):
# inspect request arguments
print(self.request.arguments)
Please let me know if you have any further question.
It's generally bad to use a character like = in a URL path fragment, since they are generally used for query arguments. Either don't use it:
`r"/users/(?P<key>\w+)"`
or turn it into a proper query argument
`r"/users/\?key=(?P<key>\w+)"`
Otherwise it's confusing for a maintainer to try to figure out which scheme you intended to use (did you really want to route a path fragment called /key%3D\w+? Or did you really mean you wanted a query arg and forgot the ??)
In any case, for URL path fragment matching ("slug-matching"), using argument unpacking can let you access them in the handler too, without having to invoke path_kwargs:
# `r"/users/(?P<key>\w+)"`
class Handler(RequestHandler):
def get(self, **kwargs):
key = kwargs.get('key')
# I prefer dict.get() here, since if you change the `+` to a `*`,
# it's possible that no key was supplied, and kwargs['key']
# will throw a KeyError exception
If you intended to use a query argument for key, then #afxentios's answer is appropriate. (You can also use self.get_query_argument('key') which will explicitly only look for query arguments in the URL (whereas get_argument also checks in the request BODY for a www-url-encoded argument (such as if you POST)).
I get this error in one of my tests:
NoReverseMatch: Reverse for 'plan' with arguments '()' and
keyword arguments '{u'month': u'201604'}' not found.
1 pattern(s) tried: ['plan(/(?P<month>[0-9]+))?$']
The call was
response = self.client.get(reverse('plan', kwargs={'month': '201604'}))
and the urlpattern
url(r'^plan(/(?P<month>[0-9]+))?$', sp_views.plan, name='plan'),
I tried to call /plan/201604 without hardcoding the url. What have I done wrong?
You need to make the outer argument non-capturing:
url(r'^plan(?:/(?P<month>[0-9]+))?$', text, name='plan'),
Personally, I always find this confusing, so I prefer to have two url patterns. I would include a trailing slash in the urls as well:
url(r'^plan/$', sp_views.plan, name='plan'),
url(r'^plan/(?P<month>[0-9]+)/$', sp_views.plan, name='plan'),
url(r'^v1/(statistics|analytics)/stats_bar$', views.stats_bar, name='stats_bar')
reverse('stats_bar')
Throws: Reverse for 'stats_bar' with arguments '()' and keyword arguments '{}' not found. 1 pattern(s) tried: ['v1/(statistics|analytics)/stats_bar$']
Is there any way to manipulate the pattern Django tries or another simple way to deal with this issue?
Django==1.6.9
I think django is interpreting (statics|analytics) as a pattern for variable. I suggest as follow:
define 2 different url to the same view:
url(r'^v1/statistics/stats_bar$', views.stats_bar, name='stats_bar_statistics')
url(r'^v1/analytics/stats_bar$', views.stats_bar, name='stats_bar_analytics')
reverse('status_bar_statistics') # usage
and inside the view test which url has been used:
if 'analytics' in request.path:
# do something
elif 'statistics' in request.path:
# do otherthing
you define one url with parameter:
url(r'^v1/ (?P<type>(statistics|analytics))/stats_bar$', views.stats_bar, name='stats_bar')
reverse('status_bar', kwargs={'type': 'statistics'}) # usage
https://docs.djangoproject.com/en/stable/ref/urlresolvers/#reverse
Look at the section about args.