#login_required and is_authenticated() -- When to use which in Django? - django

I do not see a clear distinction between using #login_required decorator and is_authenticated(): somehow, I think they perform similar checks (though not exactly).
Let say I have a function in my views.py:
def dosomethingNow(request):
if request.user.is_authenticated():
//carry out the function
else:
//redirect to login page
Same function with login_required decorator:
#login_required
def dosomethingNow(request):
//carry out the function
Both the function does similar checks except that is_authenticated(), gives the option of redirecting to homepage if not logged in.
Any other benefits of using one over the other and places where they can't be used interchangeably?
Thanks

In the way you're using them in your example code, they're essentially equivalent.
Using user.is_aunthenticated is more flexible (as you note, you can decide what to do if they're not--output a different template, redirect to a login form, redirect somewhere else, etc.)
However, #login_required is "declarative", which can be nice. You could write a script that listed all of your view functions and whether or not they had the #login_required decorator around them, for instance, so you had a nice report of "login-required" sections of your site. When the checking happens in your own code buried inside the function, you lose that kind of possibility.
So it's a really a question of development style: do you need the flexibility to handle this as a special case? Or does make sense to use a declarative style?
(And, if you wanted a different implementation but a declarative style--say,if you frequently wanted to redirect non-logged-in-users to the homepage, you could write your own decorator, #homepage_if_not_auth, and use that)

Related

django class view access response

in function view:
def view(request):
# do something with request
response = render(request, 'view.html')
# do something with response
return response
but now I have a View class:
class ArticleDeleteView(View):
pass
# or even something more complicated
class ArticleDeleteView(LoginRequiredMixin, UserPassesTestMixin, DeleteView):
pass
which function shall I overwrite to access to the response?
sorry that it may seems a silly question to you, but I looked through the docs and failed to find an answer.
thanks for all suggestions in comment. here's why I need to access to the response. Conditional Django Middleware (or how to exclude the Admin System)
I am building a specific type of 'middleware', for certain class based view, they are not actually middleware since they are not called for each request. I need to access to the response in order to do something before and after the response then return it, therefore I much would like to know which function generate response.
The easiest answer is: you don't. The View classes tend to be uncomplicated enough to be easily rewritten as a custom view which inherently gives you access to the response.
However if you insist I guess one of the functions you could override is the following: as_view, dispatch or setup as the request function goes through all of them. Sadly I couldn't find any mention of the one that was intended for that purpose.

How do you return a complete url with get_success_url(self) in django?

How do you return a url using get_success_url(self) in django without using reverse for a generic view? Basically, I want to have something as below.
def get_success_url(self):
url = self.object.url # This is a charfield with "https://stackoverflow.com/questions/ask"
return url
I know that people often use reverse when returning a url, but I would like do it like above. Thank you, and please write any questions you have. By the way, I never tested the above code, but I don't know if it will work properly.
"reverse(..)" is part of the django logic to store the url structure in urlpatterns in ONE place and then in the whole code refere to it in the moment of the request being executed via the name. If you do not want to follow that logic - feel free to store anything you like in your "object.url" and return it like you propose. You then just do not follow the django urlpattern idea. Up to you to decide if that is important or "right" in your case.
If the url targets outside our own server space, reverse is anyway not usefull as those urls are not part of your urlpattens.

Check multiple decorators before accessing a view in django

Im using #user_passes_test decorator to check whether the user has permissions to the view. Each usertype is given a function that is used with the decorator. Like this
#user_passes_test(ismanager,login_url='userauth:forbiddnpage')
#user_passes_test(isadministrator,login_url='userauth:forbiddnpage')
Now, if the first one returns false the forbidden page is shown. Is there any way i can get all the decorators to get checked before redirecting or giving access. Thanks for the help.
If you want to test multiple conditions for the same decorator, I suggest you write down a new one which uses user_passes_test and variable number of function name args. You can apply the conditions for ismanager and is_administrator and send the result in lambda to user_passes_test.
Motivation for doing this can be login_required decorator which internally uses user_passes_test in a similar way.
Also, using the same decorator multiple times like you are doing is making code dirty and is a little redundant, so this would be a better solution.

Sharing code among views in Django

Forgive me if this has been asked repeatedly, but I couldn't find an example of this anywhere.
I'm struggling to understand how to share code among view functions in Django. For example, I want to check if the user is authenticated in many views. If they're not, I'd like to log some information about that request (IP address, etc.) then display a canned message about needing authentication.
Any advice on how to accomplish this?
You can write those code in a function, then call it in many views.
For example:
def check_login():
pass
def view1():
check_login()
pass
def view2():
check_login()
pass
This is probably best accomplished by creating a utils.py file, rather than a view. Views that don't return an HTTPResponse object are not technically valid.
See: https://docs.djangoproject.com/en/dev/intro/tutorial03/#write-views-that-actually-do-something
"Each view is responsible for doing one of two things: Returning an HttpResponse object containing the content for the requested page, or raising an exception such as Http404." ... "All Django wants is that HttpResponse. Or an exception."
Heroku will throw an error if the view does not return an HttpResponse.
What I usually do in this instance is write a function in a separate file called utils.py and import it and use it from the application files that need it.
from utils import check_login
def view1(request):
check_login(request)
pass
def view2(request):
check_login(request)
pass
One simple solution would be to use decorators just like in django's login_required, however if you need something more complex maybe you want something like class based views

Can a django template know whether the view it is invoked from has the #login_required decorator?

Let's say that I have a system that has some pages that are public (both non-authenticated users and logged-in users can view) and others which only logged-in users can view.
I want the template to show slightly different content for each of these two classes of pages. The #login_required view decorator is always used on views which only logged-in users can view. However, my template would need to know whether this decorator is used on the view from which the template was invoked from.
Please keep in mind that I do not care whether the user is logged in or not for the public pages. What I care about is whether a page can be viewed by the general public, and the absence of a #login_required decorator will tell me that.
Can anyone throw me a hint on how the template would know whether a particular decorator is being used on the view from which the template invoked from?
Yes, it is possible, but not terribly straightforward. The complicating factor is that Django's login_required decorator actually passes through 2 levels of indirection (one dynamic function and one other decorator), to end up at django.contrib.auth.decorators._CheckLogin, which is a class with a __call__ method.
Let's say you have a non-django, garden-variety decorated function that looks like this:
def my_decorator(func):
def inner():
return func()
return inner
#my_decorator
def foo():
print foo.func_name
# results in: inner
Checking to see if the function foo has been wrapped can be as simple as checking the function object's name. You can do this inside the function. The name will actually be the name of the last wrapper function. For more complicated cases, you can use the inspect module to walk up the outer frames from the current frame if you're looking for something in particular.
In the case of Django, however, the fact that the decorator is actually an instance of the _CheckLogin class means that the function is not really a function, and therefore has no func_name property: trying the above code will raise an Exception.
Looking at the source code for django.contrib.auth.decorators._CheckLogin, however, shows that the _CheckLogin instance will have a login_url property. This is a pretty straightforward thing to test for:
#login_required
def my_view(request):
is_private = hasattr(my_view, 'login_url')
Because _CheckLogin is also used to implement the other auth decorators, this approach will also work for permission_required, etc. I've never actually had a need to use this, however, so I really can't comment on what you should look for if you have multiple decorators around a single view... an exercise left to the reader, I guess (inspect the frame stack?).
As unrequested editorial advice, however, I would say checking the function itself to see if it was wrapped like this strikes me as a bit fiddly. You can probably imagine all sorts of unpredictable behaviour waiting to happen when a new developer comes to the project as slaps on some other decorator. In fact, you're also exposed to changes in the django framework itself... a security risk waiting to happen.
I would recommend Van Gale's approach for that reason as something that is explicit, and therefore a much more robust implementation.
I would pass an extra context variable into the template.
So, the view that has #login_required would pass a variable like private: True and the other views would pass private: False
Why does your template need to know this? If the #login_required decorator is used, the view itself prevents people who aren't logged in from ever reaching the page and therefore never seeing the template to begin with.
Templates are hierarchical so why not have a #login_required version and a "no #login_required" version, both of which inherit from the same parent?
This would keep the templates a lot cleaner and easier to maintain.