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())
Related
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.
I am new on web development.
I am now implementing a simple create/edit user form with a submit button.
I would like to know the better practice to implement this.
I have already define this kind of web api
URL Method Description
/users/ GET Gives a list of all users
/users/ POST Creates a new user
/users/<id> GET Shows a single user
/users/<id> PUT Updates a single user
/users/<id> DELETE Deletes a single user
My first approach:
i create two new "/user/add" and "/usr/edit" function,
which similar to
app.route("/users/edit")
def edit_user(){
....
....
call the internal api /user/ with a "put" method
....
render_template("edit.html")
when I click the submit the button, the i call the above internal api /users/ ,method=PUT,
and render the final template.
My second approach:
in my internal api /user/, i try to read the http header to see if i want a html template or json text and return back to user
Say, again when i want to create a edit form, instead of calling /user/edit , i call /user/, with a PUT method
def put(self, id):
//see the header of that request
if header == html
render_template("edit.html", .....)
if header == json
update the record
#
my question , basically, i don't know if "/user/add" "/user/edit" route is necessary to make a form, or we can just simple embedded into /user/ api with different "post" or "put" method.
the idea is coming from here , from flask, pluggable view, which i am wondering how to make a better implementation
Or is that a better way to do it???
Thanks a lot.
I would choice your first approach because than your URLs are clear and logical. Also you split your frontend (Website with forms) and backend (API) which is in testing very helpful. A normal web browser makes only GET and POST requests to a website so it is very difficult to render template by a PUT request for the user because the user is normally not able to start a put request.
In my Django app I have multiple pages displaying a link that loads a new page displaying a form. When the form is submitted, what is the cleanest way to redirect to the originating page from which this form was accessed?
originating page -> form page -> originating page
Using a next variable seems unellegant since I have to set it as a GET variable on the originating page link, and then set it as a hidden POST variable in my form? Any other ideas would be appreciated.
There are a couple of options, all with the cons and benefits ofcourse.
passing the originating page withi POST/GET
storing the originating page in the session (won't work with multiple tabs obviously)
storing the originating page in a cookie (won't work with multiple tabs either)
if it's a single page, redirect to the referrer. Doesn't seem possible in your case
Personally I think using a next parameter is your best option, but do remember to secure it (only relative urls, no javascript stuff, csrf framework) so you won't have any security problems with it.
WoLpH already listed the resonable possibilities and pointed to (probably) the best of them as a solution. So I will only elaborate on it.
If you need to handle this: originating page -> form page -> originating page then in reality it will look like this: originating page --[GET]--> form page --[POST/submision]--> form page(2) --[GET/redirect]--> originating page. This means, that form page(2) stage has to somehow know where to redirect user and the only reasonable choices you have here is to use session (with the drawback mentioned by WoLpH) or to pass it in POST, possibly as a hidden field.
Regarding the first GET and passing next URL into form page, you can either pass it in the query string (which you find unelegant), or you can extract it from HTTP_REFERER header - which won't work for more paranoid users like me.
You can also do a mixed stuff here, i.e. add next=<next-URL> into the query string if and only if user hasn't turned off HTTP_REFERER in her browser. Then most users won't see any ugly stuff in URLs.
Note that all these things can be automated, i.e. you can write your links as:
<a href="{% url myform %}?{% inject_next_url %}">
When inject_next_url injects sth like: next={{ context['request'].get_full_path() }} only if HTTP_REFERER is not present.
Then, in form handler you can use some generic extract_next_url(request) function, that looks for next URL in one of: query string, HTTP_REFERER, request.POST, or more consise - in one of: HTTP_REFERER, request.REQUEST
Another option might be to create separate URL conf that resolve to the same view, and passing in the source view as a kwargs to the view.
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!
I've produced a few Django sites but up until now I have been mapping individual views and URLs in urls.py.
Now I've tried to create a small custom CMS but I'm having trouble with the URLs. I have a database table (SQLite3) which contains code for the pages like a column for header, one for right menu, one for content.... so on, so on. I also have a column for the URL. How do I get Django to call the information in the database table from the URL stored in the column rather than having to code a view and the URL for every page (which obviously defeats the purpose of a CMS)?
If someone can just point me at the right part of the docs or a site which explains this it would help a lot.
Thanks all.
You dont have to to it in the flatpage-way
For models, that should be addressable, I do this:
In urls.py I have a url-mapping like
url(r'(?P<slug>[a-z1-3_]{1,})/$','cms.views.category_view', name="category-view")
in this case the regular expression (?P<slug>[a-z1-3_]{1,}) will return a variable called slug and send it to my view cms.views.category_view. In that view I query like this:
#render_to('category.html')
def category_view(request, slug):
return {'cat':Category.objects.get(slug=slug)}
(Note: I am using the annoying-decorator render_to – it is the same as render_to_response, just shorter)
Edit This should be covered by the tutorial. Here you find the url-configuration and dispatching in every detail. The djangobook also covers it. And check pythons regex module.
Of course you can use this code.
Your question is a little bit twisted, but I think what you're asking for is something similar to how django.contrib.flatpages handles this. Basically it uses middleware to catch the 404 error and then looks to see if any of the flatpages have a URL field that matches.
We did this on one site where all of the URLs were made "search engine friendly". We overrode the save() method, munged the title into this_is_the_title.html (or whatever) and then stored that in a separate table that had a URL => object class/id mapping.ng (this means it is listed before flatpages in the middleware list).