Is there a more elegant way to write this django view? - django

I've been messing around with django and I have this django view:
def handle_results(request):
if request.method == "POST" and request.is_ajax():
# Do something with the post request
elif request.method == "GET" and request.is_ajax():
# Do something with the get request
else:
# First time in this view, render first element to display
return render(
request, "result_page.html", context={"display": arr[0]}
)
The main idea is, this is supposed to be a Same Page Application, and the first time I'm in this view, I need to render the contents of the array to display to the user, after that, the user can interact with said array via the html (think of it as upvoting or downvoting stuff that's shown). Depending on the user's choice, I get a GET or POST request and need to deal with said request.
However, the way I'm implementing this seems not that elegant and I was wondering if there'd be another better way to accomplish what I'm doing.
Thank you so much!

I would suggest using a class based view

Related

Django - Transfer data from view to form

I am struggling with the update of database information with the forms, and simply passing information between views. I could really use some advice because I am fairly new to Django.
The flow goes like this:
1. First form; I transfer the article price and title to the view "event"
2. The view "event" handles title and price and ask for confirmation in the html form
3. Once confirmed, it directs that information to the view "transact_test", I want this view to handle the update of the database via a new form that is build with the Article model. But it provides the error message : "didn't return an HttpResponse object. It returned None instead."
To fix your error: In transact_test you are just calling render in the request.method == 'POST' block:
render(request, ...)
You need to return render:
return render(request, ...)
You should really take a look at some additional django tutorials you are making this harder than you need to. You should almost never manually render a form when using django. And as Tariq said, please don't use images.

Django is there a benefit of checking every view with `method=='POST':`

Is there a benefit to starting every one of my view functions with if request.method=='POST': or if request.method=='GET':? Or would I just be adding unnecessary lines of code?
I've followed a few examples where views for Ajax are all checking if the HTTP is made with GET.
Could it, for example, prevent DDOS from latching on to a POST method and hammering it with GETs? Or, more practically, prevent API consumers from incorrectly PATCHing when they should PUT or POST?
def employee_delete(request, uid):
if request.method == 'DELETE':
def employee_detail(request, uid):
if request.method == 'GET':
def employee_create(request):
if request.method == 'POST':
def employee_update(request, uid):
if request.method == 'PUT':
Is there a benefit to starting every one of my view functions with if request.method=='POST':
Yes, even if you only support one method, it is better to guard this. The HTTP protocol specifies that GET requests, should not have side-effects (well effects in the sense of counting visitors are probably no problem, but not something that changes the "entities" of your business logic is strictly speaking not acceptable).
Now "web crawlers" (for example used by search engines or scrapers) typically detect links on a page, and make GET requests on these links (since they aim to "discover" new pages). If there is a view behind this URL that, for example, deletes an employee, it can happen that accidentally a "web crawler" will edit your database.
Other methods like GET, HEAD, PUT and DELETE should be idempotent (that means that making the same request twice, should have the same side-effects, as making the request only once).
So by not "protecting" your views, you lose a layer of "protection" against accidental misuse of your webserver.
A hacker could also aim to make a request with another method, and see how the server responds in a search to find exploits: for example, look if a server makes certain assumptions on the method that fail when performing a DELETE request. For example, a rather generic view implementation that handles all methods, could - if not guarded - unintentionally allow the deletion of files (for example you write a generic view to create and edit content can be "misused" by a hacker by using a DELETE request that the parent view implemented, but should not be supported for that specific entity).
In the early days, some HTTP webservers for example did not check authentication when a HEAD request was used. As a result, a hacker could, by trying several HEAD requests "scan" the id space, and thus obtain knowledge what id's were filled in in the database. Of course that in itself does not leak much data, but it is a vulnerability that can be used as a first step in hacking data.
Note that although Django has some protection against this when using, for example, class-based views, a person can just use any string for the request. So a person can write as method FOOBAR. If the view for example specifies if request.method == 'POST', and an else: statement, it can thus be used, to enter the else statement with a non-GET method.
But regardless of the use-case, "better be safe than sorry", and guarding the HTTP methods, is just one of the aspects to check.
That being said, if only a subset of methods are allowed, you can use the #require_http_methods [Django-doc] decorator:
from django.views.decorators.http import require_http_methods
#require_http_methods(["GET", "POST"])
def my_view(request):
# I can assume now that only GET or POST requests make it this far
# ...
pass
This decorator thus makes it more elegant to guard that the proper method is used.
To offer a different perspective, I think your question illustrates why you should consider using class-based views, which make life so much simpler when dealing with such problems.
For example the generic CreateView already comes with all the logic built in to restrict the type of HTTP request. It will let you perform a GET request to initialise a form, but require a POST request to process data. Thus you can't accidentally trigger data to be saved through a GET request.
It also provides the framework for proper form data validation, error handling etc - which you would have to implement yourself in a procedural view.
Same goes for the range of other views that Django provides - UpdateView, DetailView etc.
All Django class-based views come with a http_method_names attribute that you can use to control which methods are allowed on your views, e.g.,
from django.views.generic import View
class MyView(View):
# only GET and POST allowed. Anything else will get a 405 Method Not Allowed response.
http_method_names = ['get', 'post']
def get(self, request, *args, **kwargs):
# Logic for GET requests goes here.
def post(self, request, *args, **kwargs):
# Logic for POST requests goes here. No risk of it getting mixed up with GET.
This in addition to providing a lot of other helpers for things like form handling, template loading etc. Procedural views may feel simpler initially, but you will quickly realise that you end up having to write a lot more code to get them to do what you need.

Sending form to another view django

I am building a website and I want various views that will ask the user to request a quote from our page. I want to keep the code as DRY as possible so I am writing a view quote which will receive the quote requests from various views and, if there is a validation error redirect back to the page that made the request. I managed to solve this using the super bad practice 'global variables'. I need a better solution, I would like redirecting to respective view with the current form so I can iterate through the form.errors. Here is my code:
def send_quote(request):
form = Quote(request.POST)
if form.is_valid():
# do stuff when valid
return redirect('Support:thanks', name=name or None)
quote_for = request.POST['for_what']
global session_form
session_form = form
return redirect('Main:' + quote_for) # Here I would like to send form instead of storing in global variable`
You can use the HttpResponseRedirect function, and pass as argument the page that made the request.
return HttpResponseRedirect(request.META.get('HTTP_REFERER'))
All the META data is store on a dictionary, if you want to learn more check the documentation.
https://docs.djangoproject.com/en/dev/ref/request-response/#django.http.HttpRequest.META
If you redirect to the referrer, form.errors will be empty, as redirection is always a GET request.
I can think of two solutions to your problem:
Submit forms asynchronously using JavaScript and so populate the errors
Make all the views containing the form support POST - one way to do this would be to create a base class that inherits from FormView
The second option is a typical way of handling forms in Django - you process both POST and GET inside the same view.
After two days of searching I finally found the answer. Instead of saving form in request.session I just save request.POST and then redirect. Here is the code:
def send_quote(request):
form = Quote(request.POST)
if form.is_valid():
# do stuff when valid
return redirect('Support:thanks', name=name or None)
quote_for = request.POST['for_what']
request.session['invalid_form'] = request.POST
return redirect('Main:endview')
def endview(request):
session_form = request.session.pop('invalid_form', False)
if session_form:
form = Quote(session_form)
# render template again with invalid form ;)
Now I can repeat this with all the views I want and just change the what_for input of each form to match the respective view (Like I intended).

Django view: good programming practice question

suppose that you have a webpage that uses the post and get method, and you wrote the following view to generate it:
def homepage(request):
if 'login' in request.POST:
# ......... code goes here, and you return an appropriate response
if 'register' in request.POST:
# ......... code goes here, and you return an appropriate response
# When no Post request, just render the page
return render_to_response('homepage.html')
Question:
Is it considered good programming practice to split the above view into three views: one for login, one for register and one that would render the page? Or is it OK to keep it as it is.
EDIT
in the case listed above, I am not checking if the server received a "GET". But the idea is still the same :)
I think a better idea would be to have each of the two forms submit to a different URL. Then you can define views for, e.g., /login, /register, and / (the default homepage handler). Your views for /login and /register can use if request.method == 'POST', and then redirect to the homepage if they are called with a GET request.

Can django-piston module create upload image restful webservice

I trying to restful server that one can upload image, By use django-piston I can put,get,post information restfully but don't know how to upload image.
pretty much.
technically it's just a http post.
On the one hand, yes. If you have the image data, it's possible to send it via post to a handler that knows how to handle it; if you do it right, it should, theoretically, be available in request.FILES to your handler. Simple HTTP.
On the other hand, no. In order to do an AJAX upload like this, you would have to somehow get the image data without the user actually submitting a form. This is why "ajax upload forms" are so difficult to implement, and usually use tricks like hidden iframes to do their stuff.
To the best of my knowledge, only Firefox and its gecko kin allow this kind of access to a file field's binary content, via the File object's getAsBinary() method.
You can certainly do the POST. The file(s) will be available in the request.FILES (piston won't get in the way of this).
In order to do the PUT, we'll have to make some changes to piston to support the x-method-override header. That's what I do to allow PUT and DEL from flash. ( Don't forget to add the header when you do the POST to make it get interpreted as a PUT )
Here's some example middleware:
class x_http_methodoverride_middleware():
def process_request(self, request):
if 'HTTP_X_HTTP_METHODOVERRIDE' in request.META:
newMethod = request.META['HTTP_X_HTTP_METHODOVERRIDE']
if 'PUT' == newMethod.upper():
request.method = 'PUT'
request.META['REQUEST_METHOD'] = 'PUT'
request.PUT = request.POST
if 'DELETE' == newMethod.upper() or 'DEL' == newMethod.upper():
request.method = 'DELETE'
request.META['REQUEST_METHOD'] = 'DELETE'
request.DELETE = request.POST
( the code is from an open piston ticket here http://bitbucket.org/jespern/django-piston/issue/83/use-x-http-method-override-to-override-put )
You can find two answers here: http://groups.google.com/group/django-piston/browse_thread/thread/6f3f964b8b3ccf72/bd1658121bb1874c?show_docid=bd1658121bb1874c&pli=1
One way is to use request.FILES to get the filename, and then to save the image:
def create(self, request, nickname):
name = request.FILES["image"].name
image = PIL.Image.open(request.FILES["image"])
image.save(SOME_PATH+name)
return rc.ALL_OK
The second suggestion is to define an Image model and an ImageForm form, and use those:
def create(self, request, nickname):
form = ImageForm(request.POST, request.FILES)
if form.is_valid():
Image.objects.create(image=form.cleaned_data['image'])
return rc.ALL_OK
return rc.BAD_REQUEST
WARNING: I haven't tested either of these methods!