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
Related
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.
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.
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)
Apologies if my question is very similar to this one and my approach to trying to solve the issue is 100% based on the answers to that question but I think this is slightly more involved and may target a part of Django that I do not fully understand.
I have a CMS system written in Django 1.5 with a few APIs accessible by two desktop applications which cannot make use of cookies as a browser does.
I noticed that every time an API call is made by one of the applications (once every 3 seconds), a new entry is added to django_session table. Looking closely at this table and the code, I can see that all entries to a specific URL are given the same session_data value but a different session_key. This is probably because Django determines that when one of these calls is made from a cookie-less application, the request.session._session_key is None.
The result of this is that thousands of entries are created every day in django_session table and simply running ./manage clearsessions using a daily cron will not remove them from this table, making whole database quite large for no obvious benefit. Note that I even tried set_expiry(1) for these requests, but ./manage clearsessions still doesn't get rid of them.
To overcome this problem through Django, I've had to override 3 Django middlewares as I'm using SessionMiddleware, AuthenticationMiddleware and MessageMiddleware:
from django.contrib.sessions.middleware import SessionMiddleware
from django.contrib.auth.middleware import AuthenticationMiddleware
from django.contrib.messages.middleware import MessageMiddleware
class MySessionMiddleware(SessionMiddleware):
def process_request(self, request):
if ignore_these_requests(request):
return
super(MySessionMiddleware, self).process_request(request)
def process_response(self, request, response):
if ignore_these_requests(request):
return response
return super(MySessionMiddleware, self).process_response(request, response)
class MyAuthenticationMiddleware(AuthenticationMiddleware):
def process_request(self, request):
if ignore_these_requests(request):
return
super(MyAuthenticationMiddleware, self).process_request(request)
class MyMessageMiddleware(MessageMiddleware):
def process_request(self, request):
if ignore_these_requests(request):
return
super(MyMessageMiddleware, self).process_request(request)
def ignore_these_requests(request):
if request.POST and request.path.startswith('/api/url1/'):
return True
elif request.path.startswith('/api/url2/'):
return True
return False
Although the above works, I can't stop thinking that I may have made this more complex that it really is and that this is not the most efficient approach as 4 extra checks are made for every single request.
Are there any better ways to do the above in Django? Any suggestions would be greatly appreciated.
Dirty hack: removing session object conditionally.
One approach would be including a single middleware discarding the session object conditional to the request. It's a bit of a dirty hack for two reasons:
The Session object is created at first and removed later. (inefficient)
You're relying on the fact that the Session object isn't written to the database yet at that point. This may change in future Django versions (though not very likely).
Create a custom middleware:
class DiscardSessionForAPIMiddleware(object):
def process_request(self, request):
if request.path.startswith("/api/"): # Or any other condition
del request.session
Make sure you install this after the django.contrib.sessions.middleware.SessionMiddleware in the MIDDLEWARE_CLASSES tuple in your settings.py.
Also check that settings.SESSION_SAVE_EVERY_REQUEST is set to False (the default). This makes it delay the write to the database until the data is modified.
Alternatives (untested)
Use process_view instead of process_request in the custom middleware so you can check for the view instead of the request path. Advantage: condition check is better. Disadvantage: other middleware might already have done something with the session object and then this approach fails.
Create a custom decorator (or a shared base class) for your API views deleting the session object in there. Advantage: responsibility for doing this will be with the views, the place where you probably like it best (view providing the API). Disadvantage: same as above, but deleting the session object in an even later stage.
Make sure your settings.SESSION_SAVE_EVERY_REQUEST is set to False. That will go a long way in ensuring sessions aren't saved every time.
Also, if you have any ajax requests going to your server, ensure that the request includes the cookie information so that the server doesn't think each request belongs to a different person.
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.