Difference between prepend_urls and urlpatterns in urls.py - django

I have a REST API on Django with TastyPie, which includes on a resource, say ProductResource. This resource is accessible via http://my_url/api/product.
I also have a function in my ProductResource class called addNew which is supposed to handle requests to add new Product. I want to link this method to a url such as http://my_url/api/product/new.
One option is to override prepend_urls like this:
def prepend_urls(self):
return [
url(r"^(?P<resource_name>%s)/addNew%s$" %
(self._meta.resource_name, trailing_slash()),
self.wrap_view('addNew'), name="product_add_new"),
]
This works as expected. I assume the other option is to use urls.py, and define the end point there. I have tried to do so, and have added this line to my urlpatterns:
url(r"^(?P<resource_name>ProductResource)/addNew/$", ProductResource.addNew, name="product_add_new")
When I do this, I get the following error:
unbound method addNew() must be called with ProductResource instance as first argument (got WSGIRequest instance instead)
Which is understandable. So my question is if it's possible to bind a method inside a resource to a url via urls.py instead of prepend_urls? if yes, what would be the correct syntax? if no, what is the difference between prepend_urls and urls.py?
Thanks

Well, you can't map a method like addNew to a url directly because a callable used in url() must receive as first argument a request. If you really want to map a url to a resource method you could do:
def my_view(request):
resource = MyResource(api_name='myapi')
resource.addNew(request)
And then map this view in url()
url(r"^(?P<resource_name>ProductResource)/addNew/$", my_view, name="product_add_new")
About prepend_urls() what happens is that what you use as a callable in your url() is the return of the wrap_view(), not the method itself. And what wrap_view() returns is a callable that takes a request as its first argument.
https://github.com/django-tastypie/django-tastypie/blob/master/tastypie/resources.py#L188

Related

Django: pass some paremeter to view in Django urls

I want to pass some string for some urls to my views in django
Suppose i have
path('someurl/', someview , name='someurl'),
I want to pass some string to someview, when this url is called so is this possible
path('someurl/', someview(somevar="test") , name='someurl'),
and then i have the view
def someview(request, somevar):
access somevar here
Is this possible in Django urls.
If you wish to accept parameter from the client, update your path as below:
path('someurl/<str:somevar>/', someview , name='someurl')
And view now can accept extra parameter:
def someview(request, somevar):
# now you can use somevar
With this definition, if client requests somevar/urlparam/, "urlparam" will be passed to you view function.
Otherwise if you want to provide your own argument, Django doesn't provide the way to do it directly in url definition. But, since that variable is your own one, why don't assign (or compute) that in view? I mean:
def someview(request):
somevar = "test" # or you may call some function for dynamic assignment
# now somevar exists in this scope, so you can use it as you want
yes it is possible. You need to define those parameters in the url as pseudo path:
path('articles/<int:year>/<int:month>/', views.month_archive),
There is also an option to use request.GET and request.POST to access the optional parameters list in the url:
request.POST.get('<par name here>','<default value here>')
request.GET.get('<par name here>','<default value here>')
Another thing you may find useful is this question.

Get argument from route function in my own decorator in flask

In the flask, between the route function and the view function, how can I obtain the argument so that I can define a new decorator? Here I show an example.
#app.route('/Page/<int:Num>')
#HowToGetNum(Num) # here I do not know how to get Num
def Page(Num):
....
The parameter Num will be passed into Page. But before that, I want to define a new decorator "HowToGetNum". However, I found there is no way to pass Num into it. Any solutions?
In python decorator operate on the function before they are used.
What's actually going on is the Page function is being redefined.
Page = HowToGetNum(Page)
What you can do is define HowToGetNum as:
def HowToGetNum(func):
def GetsNum(Num):
# do something with Num
func(Num)
return GetsNum
So the new function has your functionality then runs the original Page

Django URLs: How to handle a parameter

In my url.py i have the following line:
url(r'^mypage/(?P<q_id>\d+)/$', QuizWizard.as_view(generate_form_tuples()), name='nickname'),
QuizWizard is a SessionWizardView
generate_form_tuples is a function (defined inside this module, which has an optional parameter):
def generate_form_tuples(q_id=1):
...
So, when you get on mypage/ you will (maby) have a q_id.
How can i get this parameter from the url and pass it to the generate_form_tuples() function ?
P.S. I know that if I redirect this to be handled in a view, the parameter will be sent automatically having as name : q_id
One way is to redesign it a bit, like this:
url(r'^mypage/(?P<q_id>\d+)/$', generate_form_tuples, name='nickname'),
...
def generate_form_tuples(request, q_id=1):
...
return QuizWizard.as_view(...)(request, q_id=q_id)

Django-- Retrieve specific object in templates

I'm trying to have the URL have a variable (say userid='variable') and that variable would be passed as an argument to retrieve a specific object with 'variable' as its name in some specific application's database. How would I do this?
Arie is right, the documentation for Django is excellent. Don't be intimidated, they make it very easy to learn.
From the Writing your first Django app, part 3 (https://docs.djangoproject.com/en/dev/intro/tutorial03/), the example shows you how to capture variables from the URL.
In urls.py:
urlpatterns = patterns('',
(r'^polls/$', 'polls.views.index'),
(r'^polls/(?P<poll_id>\d+)/$', 'polls.views.detail'),
)
the line (r'^polls/(?P<poll_id>\d+)/$', 'polls.views.detail') says when the url is like mysite.com/polls/423, capture the \d+ (the 423) and send it to the detail view as variable named poll_id. If you change <poll_id> to <my_var>, the variable named my_var is passed to the view. In the view, the example has:
def detail(request, poll_id):
return HttpResponse("You're looking at poll %s." % poll_id)
You in the body of this function, you could look up the poll Polls.objects.get(id=poll_id) and get all of the properties/methods of the Poll object.
ALTERNATIVELY, if you are looking to add URL variables (query string), like /polls/details?poll_id=423, then your urls.py entry would be:
(r'^polls/details$', 'polls.views.detail'),
and your view:
def detail(request):
poll_id = request.GET['poll_id']
return HttpResponse("You're looking at poll %s." % poll_id)
In the body, you could still get details of the Poll object with Poll.objects.get(id=poll_id), but in this case you are creating the variable poll_id from the GET variable instead of allowing Django to parse from the url and pass it to the view.
I would suggest sticking with the first method.
Did you actually read the tutorial for Django?
To highlight just one sentence from Write your first view
Now lets add a few more views. These views are slightly different,
because they take an argument (which, remember, is passed in from
whatever was captured by the regular expression in the URLconf)

Capturing URL parameters in request.GET

I am currently defining regular expressions in order to capture parameters in a URL, as described in the tutorial. How do I access parameters from the URL as part the HttpRequest object?
My HttpRequest.GET currently returns an empty QueryDict object.
I'd like to learn how to do this without a library, so I can get to know Django better.
When a URL is like domain/search/?q=haha, you would use request.GET.get('q', '').
q is the parameter you want, and '' is the default value if q isn't found.
However, if you are instead just configuring your URLconf**, then your captures from the regex are passed to the function as arguments (or named arguments).
Such as:
(r'^user/(?P<username>\w{0,50})/$', views.profile_page,),
Then in your views.py you would have
def profile_page(request, username):
# Rest of the method
To clarify camflan's explanation, let's suppose you have
the rule url(regex=r'^user/(?P<username>\w{1,50})/$', view='views.profile_page')
an incoming request for http://domain/user/thaiyoshi/?message=Hi
The URL dispatcher rule will catch parts of the URL path (here "user/thaiyoshi/") and pass them to the view function along with the request object.
The query string (here message=Hi) is parsed and parameters are stored as a QueryDict in request.GET. No further matching or processing for HTTP GET parameters is done.
This view function would use both parts extracted from the URL path and a query parameter:
def profile_page(request, username=None):
user = User.objects.get(username=username)
message = request.GET.get('message')
As a side note, you'll find the request method (in this case "GET", and for submitted forms usually "POST") in request.method. In some cases, it's useful to check that it matches what you're expecting.
Update: When deciding whether to use the URL path or the query parameters for passing information, the following may help:
use the URL path for uniquely identifying resources, e.g. /blog/post/15/ (not /blog/posts/?id=15)
use query parameters for changing the way the resource is displayed, e.g. /blog/post/15/?show_comments=1 or /blog/posts/2008/?sort_by=date&direction=desc
to make human-friendly URLs, avoid using ID numbers and use e.g. dates, categories, and/or slugs: /blog/post/2008/09/30/django-urls/
Using GET
request.GET["id"]
Using POST
request.POST["id"]
Someone would wonder how to set path in file urls.py, such as
domain/search/?q=CA
so that we could invoke query.
The fact is that it is not necessary to set such a route in file urls.py. You need to set just the route in urls.py:
urlpatterns = [
path('domain/search/', views.CityListView.as_view()),
]
And when you input http://servername:port/domain/search/?q=CA. The query part '?q=CA' will be automatically reserved in the hash table which you can reference though
request.GET.get('q', None).
Here is an example (file views.py)
class CityListView(generics.ListAPIView):
serializer_class = CityNameSerializer
def get_queryset(self):
if self.request.method == 'GET':
queryset = City.objects.all()
state_name = self.request.GET.get('q', None)
if state_name is not None:
queryset = queryset.filter(state__name=state_name)
return queryset
In addition, when you write query string in the URL:
http://servername:port/domain/search/?q=CA
Do not wrap query string in quotes. For example,
http://servername:port/domain/search/?q="CA"
def some_view(request, *args, **kwargs):
if kwargs.get('q', None):
# Do something here ..
For situations where you only have the request object you can use request.parser_context['kwargs']['your_param']
You have two common ways to do that in case your URL looks like that:
https://domain/method/?a=x&b=y
Version 1:
If a specific key is mandatory you can use:
key_a = request.GET['a']
This will return a value of a if the key exists and an exception if not.
Version 2:
If your keys are optional:
request.GET.get('a')
You can try that without any argument and this will not crash.
So you can wrap it with try: except: and return HttpResponseBadRequest() in example.
This is a simple way to make your code less complex, without using special exceptions handling.
I would like to share a tip that may save you some time.
If you plan to use something like this in your urls.py file:
url(r'^(?P<username>\w+)/$', views.profile_page,),
Which basically means www.example.com/<username>. Be sure to place it at the end of your URL entries, because otherwise, it is prone to cause conflicts with the URL entries that follow below, i.e. accessing one of them will give you the nice error: User matching query does not exist.
I've just experienced it myself; hope it helps!
These queries are currently done in two ways. If you want to access the query parameters (GET) you can query the following:
http://myserver:port/resource/?status=1
request.query_params.get('status', None) => 1
If you want to access the parameters passed by POST, you need to access this way:
request.data.get('role', None)
Accessing the dictionary (QueryDict) with 'get()', you can set a default value. In the cases above, if 'status' or 'role' are not informed, the values ​​are None.
If you don't know the name of params and want to work with them all, you can use request.GET.keys() or dict(request.GET) functions
This is not exactly what you asked for, but this snippet is helpful for managing query_strings in templates.
If you only have access to the view object, then you can get the parameters defined in the URL path this way:
view.kwargs.get('url_param')
If you only have access to the request object, use the following:
request.resolver_match.kwargs.get('url_param')
Tested on Django 3.
views.py
from rest_framework.response import Response
def update_product(request, pk):
return Response({"pk":pk})
pk means primary_key.
urls.py
from products.views import update_product
from django.urls import path
urlpatterns = [
...,
path('update/products/<int:pk>', update_product)
]
You might as well check request.META dictionary to access many useful things like
PATH_INFO, QUERY_STRING
# for example
request.META['QUERY_STRING']
# or to avoid any exceptions provide a fallback
request.META.get('QUERY_STRING', False)
you said that it returns empty query dict
I think you need to tune your url to accept required or optional args or kwargs
Django got you all the power you need with regrex like:
url(r'^project_config/(?P<product>\w+)/$', views.foo),
more about this at django-optional-url-parameters
This is another alternate solution that can be implemented:
In the URL configuration:
urlpatterns = [path('runreport/<str:queryparams>', views.get)]
In the views:
list2 = queryparams.split("&")
url parameters may be captured by request.query_params
It seems more recommended to use request.query_params. For example,
When a URL is like domain/search/?q=haha, you would use request.query_params.get('q', None)
https://www.django-rest-framework.org/api-guide/requests/
"request.query_params is a more correctly named synonym for request.GET.
For clarity inside your code, we recommend using request.query_params instead of the Django's standard request.GET. Doing so will help keep your codebase more correct and obvious - any HTTP method type may include query parameters, not just GET requests."