Duplicate views or add parameters - django

I want to build a django application where the users are workers in a callcenter. When they talk to a client they have a specific task, but at some point they optionally might need to update the client's contact data.
The point is that there already is a view for updating the contact data. The only thing that would need to change (at the moment) is the URL you get send to after submit/cancel. So I am wondering whether I should reuse that view. I can think of roughly three options:
Reuse the view and pass the return URL as parameter
Create a new view that reuses parts of the existing view (e.g. template)
Create a completely new view
What would you recommend and why?

Option number one seems to be fine, because it reuses a lot of code. But I think it'd be a bit better to not to send such URL by parameter (an advantage that I can see: user wouldn't know the redirect URL if POST is failed).
If there are just 2 options where the user is redirected, you could consider sending boolean parameter, sth like url?during_call=1. And then in your view you could add a small ifology:
def view(request):
# your logic here
during_call = request.POST.get('during_call', False)
redirect_url = 'url1' if during_call else 'url2'
return redirect(redirect_url)

Related

Handle simple requests asynchronously through Django REST or by another method?

Firstly, sorry if the question is so obviously (I'm quite newbie). I have a Django project where the user can add or remove, for example, interests to his/her profile (ManyToMany relationship). I've achieve this with 3 views. The first one where the profile's interests are rendered, the second one to add (nothing is rendered, when the user click a link, the view just update the profile and return the first view, the one with the profile's interests) and the third one to remove interest.
urls.py
path('home/overview/add/<int:interest_pk>', add_view, name="add_view"),
views.py
def add_view(request,interest_pk): #the third (the one to remove) view is similar
user = request.user
user.profile.interests.add(Category.objects.filter(pk= category_pk).get())
return redirect('overview') #Overview is the view where the interests are rendered
This works but now I'd like to improve this making it asynchronously. So here is my question, should I use Django Rest Framework to handle this kind of request (the ones related to the POST and DELETE methods) or is there any other method?
Note: I'm not using forms to send the information (I'd rather not to use it because it's simpler to send in an url the pk of the interest and handle it in a view) and I think it could be achieved using only requests. (Correct me if I'm wrong)

GET requests to a POST handling view

I have a view intended to deal only with POST requests that starts with
user = User.objects.get(username=request.POST['name'])
Do I need to ensure the view is not invoked with a GET request? Not sure if I'm thinking about good practice/security-type things or being OCD.
I'm using the #require_POST decorator because invoking the view with GET results in "Key 'name' not found in <QueryDict: {}> and a 500 error.
I suppose the only chance of this happening is if a user looked at the HTML of the page and for some reason thought to try the action attribute of the form in the address bar -which seems unlikely.
I've tried this myself with a couple of sites and got a error page, rather than a blank page with 405 error that #require_POST gives me.
Perhaps it's good practice to guard against GET requests in case a template designer mistakenly makes a hyperlink to my view or forgets method="post"? (In which case, I suppose I should use get_object_or_404 above)
I assume adding #require_GET to views that are only designed to deal with GET requests is unnesessary?
It seems like you understand why you would want to use #requirePOST. Another option, if you did not want to cause an error on GET, is to use something along these lines:
def view(request):
if request.method == 'POST':
..code for post..
else:
*redirect, or other code*
As to whether or not you need to use #requireGET, the only way it could hurt is if you need a view to perform both GET and POST. ie a form that causes action on POST, but is simply displayed for the user on GET. But if you are requiring GET then there should not be anything in the view that could be compromised via a POST.
Do I need to ensure the view is not invoked with a GET request? Not
sure if I'm thinking about good practice/security-type things or being
OCD.
Yes. I think you touch on answering your own question. your view requires request.POST a get request errors. If you wnat to create bug free code you will ensure that no get requests access this view. Django provides a convenient, pythonic, decorator to do this. I don't think you are being OCD at all. Also, I don't know how expensive it is to trigger an error in production (emails you, logs it, etc) but that is something to consider.
I suppose the only chance of this happening is if a user looked at the HTML of the page and for some reason thought to try the action
attribute of the form in the address bar -which seems unlikely.
I dont think it matters HOW a user could make a GET request to this, i think it only matters that this view MUST be a post request.
Perhaps it's good practice to guard against GET requests in case a
template designer mistakenly makes a hyperlink to my view or forgets
method="post"? (In which case, I suppose I should use
get_object_or_404 above)
In this case i dont' think thinking about the many ways a get request could be made to this view is important. The important part is it REQUIRES a Post request. You can use the tools at your disposal to ensure that all requests entering the function are post requests.
One thing is, name is not assumed. You could still get a KeyError. Even though you are ensuring that the request is POST you can't ensure that the post request will have a parameter name
that is why get is used so frequently
if not request.POST.get('name'):
# raise some sort of error?
user = User.objects.get(username=request.POST['name'])

Django Registration and content from other views

My situation is as follows.
I have a django app that is a CMS, and this one app generates page content and menus.
There is 'default' view that generates all the page content. One of the fields of the main model is designed to limit the visibility of pages depending on the setting:
'internal' (limited to users on our network),
'worldwide' (viewable by the www) and now, I would like to add an extra value
'secure', which would limit viewing only to those who are logged in to the site.
I dont think #login_required would work, as it only works on whole functions.
We want the author or editor to be able to set this flag, rather than code a special function; and there will be instances where a page migrates from 'internal' to 'secure' then to 'worldwide' - so ideally the urls should stay the same.
What is the best way to go about this?
thanks in advance... patrick
As you want the flag set on your object, I'm assuming that flag can't be read until you're already within the view (i.e. you won't be storing it in something accessible by the request object, like a session), so that precludes custom decorators. You could choose to go with something a bit crude but workable like this:
if (val=="internal" and inrange(request.META['REMOTE_ADDR'])) or (val=="secure" and request.user.is_authenticated()) or val=="worldwide":
return render_to_response .... etc.
else:
return HttpResponseForbidden()
Substituting your model values, and writing the inrange function, naturally.
The more sophisticated approach, though, would be to write custom middleware and use the process_view() function. See the docs for more details.

Should I use Middleware or write a decorator for this?

I have a situation where a user will be asked to enter their postal code, once they do then they are redirected to the site with content relevant to the postal code they've entered in. There will be categories etc. In a nutshell, the user will see content only relevant to their area.
PLAN --
I want to store their postal code in a cookie and re-use it every time they come back to the site, of course if there is no postal code they should be directed to enter it in a form. The form will be presented before any other content will be.
My questions are should I use a decorator for this and decorate the views with a custom decorator? Or should write middleware? if I write a custom middleware for this should I use process_request process_view, it seems to me process_request gets called on EVERY request, this may pose a problem.
Thanks!
JeffC
If you want to avoid repetition, you'll need to write a middleware. If it's on EVERY page as you say, and the ZIP code is a prerequisite for using the site, then having a middleware call process_request on every request isn't necessarily a bad thing.
On the other hand, is this necessary? Couldn't your URLs just read like: /blah/12345/videos/? Then instead of having to rely on a cookie for a bookmark, your users can just remmber that page. That would negate your having to write a view, as well.
The main question here is how often will you need to use the ZIP code from the cookie. Will it affect the whole site? Or only one part of it?
If the "ZIP-oriented" content will be used only in one part (one or more, but not the whole application), then go for the decorator. It should check for the cookie and if it's not present - redirect to the ZIP selection form. If it's present - continue processing the view in which you will be able to access the ZIP code and use it accordingly.
If the ZIP code is really going to affect the majority of your service and you don't want to decorate every single view - you can go for the middleware. But you are right - it will be called on every request, so be sure it's absolutely necessary.

where do functions that don't display go in django

I have some links on an html page like , , currently I handle them as so
<p> rate down
and have a url.py entry:
(r'^cases/(?P<case_id>\d+)/case_rate/(?P<oper>.)$', 'mysite.cases.views.case_rate'),
then I have a view function that handles the logic and hits the DB, then does this:
return HttpResponseRedirect(request.META.get('HTTP_REFERER','/'))
I's there a better way to do this? I can see how this would be OK because it does have to redraw the screen to show the new rating...
The typical way to handle this is with an ajax request.
Instead of a link, you put a javascript handler that calls a view, wich updates the db, and returns a json / xml object with the new rating for the item. Then another javascript handle receives that response and updates the rating number on the screen, without a page reload.
Ideally, you'll keep both versions: plain html (the one you currently have) and the ajax one. The ajax one can be attach to the element after page load, so if javascript is not available, you'll still have a working site.
Then, regarding organization, you can have an "ajax" parameter on your view. The view should update the db accordingly, and if it's an ajax call, return the json / xml response, otherwise, return the new page. That way you can keep the logic (fetching the object, updating the db) on one place.
If you're asking whether case_rate should still go in the views.py given that it returns a redirect rather than providing content, the answer is yes, since case_rate is handling an request and returning a response.
But consider a situation where you had two view functions in views.py that had some duplicate code, and you chose to factor that duplicate code into another function that didn't both take request and return a response. Would that be fair game to leave in views.py? Sure, if moving it elsewhere would make the code harder to read. Or you might choose to put it elsewhere. It's really your call based on your sense of taste.