In my Falcon app I would like to register a route like this:
app.add_route("/more_details/{some_id}", handler)
The problem is, that the part of some_id might contain an arbitrary number of slashes. So the url might be /more_details/123/456 or /more_details/12/34/56/78 or just /more_details/1234. I would like to get 123/456, 12/34/56/78 and 1234 as some_id. Is that possible at all in Falcon? If yes, how?
Assuming you want to access the url detail in the view handling the request (handler) you can use either the uri or url attribute of the request argument in the method for the handler. Obviously you would need to do your own processing in the view to get the information you need from the url.
Related
I'm working with DRF and I'm struggling to create a URL like this:
/myApp/languages/<language_id>/countries/<country_id>/
Thanks to a previous question, I know that I can easily use the #action method decorator within DRF router's extra actions, to handle URLs with this format:
/myApp/languages/<language_id>/countries/
However, I haven't found a way to register the new URL that I need, where I include an ID for the second resource:
/myApp/languages/<language_id>/countries/<country_id>/
How can I do it with DRF?
Instead of
/myApp/languages/<language_id>/countries/<country_id>/
Please try below:
/myApp/languages/countries/<language_id>/<country_id>/
I am new to Django REST Framework... but am figuring it out via the tutorials, quick start, internet and fiddling. However, I did not find a clear solution to the following problem.
Suppose one wishes to write an api that requires an integer.
Using Django's path in the url patterns one might try:
urlpatterns = [
...
path('my_api/<int:integer_argument>', views.my_api, name='my_api'),
...
]
and in their view
#api_view(['GET'])
def my_api(request, integer_argument):
# do stuff
return JsonResponse({'int': integer_argument})
Note: here I use JsonResponse just to keep this simple, but most likely that/those argument(s) go into a class/model and into serializer to be returned by Response(serializer.data).
So now if they were to test an application which calls this api (in development mode) http://localhost:8000/my_api/1 they should get {'int':1}.
However, if they were to call http://localhost:8000/my_api/e they get the either the debug page or Bad Request (400) as html.
Lets assume that the person making the api did have proper error handling in place for to validate the arguments (in this case that integer_argument is an integer).
Now path is getting in the way, whereas for a django website this might be the desired result.
What is the RESTful and django REST framework endorsed way to handle this situation?
The path convert (e.g. <int:arg_name>) makes the url conf readable and thus is a nice feature to have.
Should I just move the types to type annotations in the function based view? and use generic slugs?
Note: in this case I want every request to my_api/<something> to return a uniform response (error or otherwise).
Your question lacks clarity. You state:
Lets assume that the person making the api did have proper error handling in place for to validate the arguments (in this case that integer_argument is an integer).
Yeah that would be Django handling things.... Which is why you get the debug page \ Bad Request because it doesn't match.
In your API you're defining endpoints which match that format - precisely. If a uri doesn't match then that's expected behavior you shouldn't be doing any wizardry here because that just doesn't make sense.
If you want to use type annotations sure - mypy is useful and other devs may find it useful as well.
Now for the next bit:
Note: in this case I want every request to my_api/ to return a uniform response (error or otherwise).
So.... add an endpoint which acts as a catch all to return that uniform response when the other path \ regular expression paths fail to find a match. I think you're overcomplicating this.
I am implementing a search form in Django. I can do a POST or a GET request. Each has their use-cases (POST request, if I want to change data on the server, GET request, if I just want to get data from the server).
Via POST request (the search keywords are not visiable in the URL, but rather in a dict in request.POST); cons: I cannot bookmark the search
via GET request (the search keywords are visible in the URL, for intance localhost:8000/books/?author=schultz); cons(?): the part ?author=schultz cannot be processed by the URL handler (see [2] below). I need to read the data from request.GET.get("author", None) in my view function.
or directly in the URL like so: localhost:8000/books/search/author/schultz ?
The author in [1] says, that Django's preferred way to handle a URL is not via GET (like so: /category_check_view/?item_id=2, but rather like so /category_check_view/2)
If I would like to implement search like this: localhost:8000/books/author/schultz, then I would have to process a GET request, read the params ?author=schultz via request.GET.get("author", None) and in my view do a redirect from this URL localhost:8000/books (in which I have a form and a GET request) to this localhost:8000/books/author/schultz.
Does this approach make sense? Or am I overcomplicating things? Just leave it at a GET request to implement my search form?
[1] Yuval Adam says in this post that
GET params are not processed by the URL handler, but rather passed
directly to the GET param dict accessible in a view at request.GET.
The Django (i.e. preferred) way to do handle URLs is the first one.
[2] Django docs: What the URLconf searches against
First things first, GET is for reading data and POST is for creating. Since search is a form of reading data, you will use GET!
Which takes us to the matter of the urls. There are as you mention 2 distinct ways to pass parameters via a url in Django:
Parameters as part of url:
Your url regex must look like this:
url(r'^books/author/(?P<author>\w+)/$',
'yourviewname',
name='author_search'
)
Your URLs will have the shape: /books/author/author_name_here
GET Parameters:
Your url regex can look like this:
url(r'^books/$',
'yourviewname',
name='book_search'
)
Your URLs will have the shape: /books/?author=author_name_here&other=other_param
It is a matter of choice mostly on what you want to use. To quote a great answer:
Don't obsess over the beauty of your URIs, they are a tool not a piece of art.
- #Quentin -
For a short implementation example of both the above mentioned ways, take a look at this link
Also usable is:
from django.urls import path
import <your_view> from views.py
path('news/<str:author>/', <your_view>.as_view())
So this is the first time I use djangorestframework-bulk for implementing batch requests. If I understand correctly, you should be able get this functionality out-of-the-box by just having your *ViewSet classes inherit also from the app's mixins like BulkUpdateModelMixin or viewsets like BulkUpdateAPIView.
As stated on the notes in the repo:
Most API urls have two URL levels for each resource:
url(r'foo/', ...)
url(r'foo/(?P<pk>\d+)/', ...)
The second url however is not applicable for bulk operations because
the url directly maps to a single resource. Therefore all bulk generic
views only apply to the first url.
However, when I try to perform PUT or PATCH bulk requests (haven't tried with DELETE) to an endpoint in my app, like:
http://localhost:8000/api/users/
I get the following error:
PUT http://localhost:8080/api/users/ 405 (METHOD NOT ALLOWED)
Is there any additional configuration I need to do in order for this url to allow PUT and PATCH requests and have my viewset's update() and partial_update() process such requests?
Thanks!!
Your problem is that you've implemented the bulk methods through the BulkUpdateModelMixin, but you don't have a proper router for your ViewSet. You now need, for example, put to go to bulk_update rather than just update.
Check out here for an example of how to set up your own router to allow for bulk update functionality with DRF ViewSets. Basically, map out the verbs to call the proper method.
I have a Django project. Given a url, how can I know which view will be dispatched to handle the request?
You want django.core.urlresolvers.resolve, which allows you to map an URL to a view and to keep your URL & view logic separate. This is the opposite of django.core.urlresolvers.reverse which allows you to map a view to a URL.
See the documentation for how to use it!