Exclude middleware from caching - django

I have very simple middleware that track numbers of "hits" of an object.
class HitCount():
def process_view(self, request, view_func, view_args, view_kwargs):
if request.resolver_match.url_name == 'article_view':
try:
Article.objects.filter(slug=view_kwargs['slug']).update(hit_count=F('hit_count')+1)
except:
pass
The problem is, it doesn't work properly when "per-site" cache is enabled.
"hit_count" field (PositiveIntegerField) is updated only once per 5 minutes (cache timeout 300s), no matter how many times page was visited during that "5 minutes".
It doesnt have to be accurate, beacuse "hit_count" field isn't even displayed on front side. I need it only, to order articles via popularity. But "5 minutes measurement error" is too much.
How can I exclude that middleware from caching? Do I need to disable cache for whole view?
settings file, I tried to change middleware order, but no effect.
MIDDLEWARE_CLASSES = (
'django.middleware.cache.UpdateCacheMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'django.middleware.security.SecurityMiddleware',
'blog.middleware.HitCount',
'django.middleware.cache.FetchFromCacheMiddleware',
)
view
class ArticleDetailView(DetailView):
queryset = Article.objects.published()
template_name = 'article.html'

The FetchFromCache middleware is fetching the page from the cache during process_request.
That means that the process_view middleware is never called.
You could try changing your middleware to override process_request instead. However, that might be tricky, because you won't have access to request.resolver_match.

Related

Django csrf token not refreshed after first login

I have hosted a website at http://cognezic-dev.ap-south-1.elasticbeanstalk.com/login/. On closer inspection, the form has the same csrf token across page refreshes and browsers, which I suspect to be the cause of the issue,this works fine on the local django server.Dont know where this is being cached. I have added CSRF Middleware in the settings.py too.
You can use the test credentials as username bismeet and password bis12345 for testing.
I have also tried creating a custom middleware as follows:
from django.middleware.csrf import rotate_token, CsrfViewMiddleware
from django.utils.deprecation import MiddlewareMixin
class CSRFRefresh(CsrfViewMiddleware,MiddlewareMixin):
def process_response(self, request, response):
print("Custom MiddleWare called")
rotate_token(request)
return response
But it still fails.
My settings.py with custom middleware contains:
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'solvesto.middleware.csrf_refresh.CSRFRefresh'
]
If not using the custom middleware,I use:
'django.middleware.csrf.CsrfViewMiddleware'
instead of
'solvesto.middleware.csrf_refresh.CSRFRefresh'
The only last resort I see to make this work is to remove csrf altogether,which is of course,bad for security.
I removed the csrf security,no other solution,works now.

Delete header in django rest framework response

I'm trying to delete Server header from django rest framework response, but I didn't find an easy way, so I create a middleware to delete it.
This is my first try:
middleware.py
class RemoveHeaders(object):
def process_response(self, request, response):
response['Server'] = ''
return response
This middleware works ok, but the problem is that it fills server header with empty string and not delete it. so I tried the next:
class RemoveHeaders(object):
def process_response(self, request, response):
del response['Server']
return response
But It doesn't work. server header continues.
How can I delete server header?, or do you know another alternative?
thanks
Updated, these are my middlewares, maybe someone is override server header, case it doesn't exist?
MIDDLEWARE_CLASSES = (
'corsheaders.middleware.CorsMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'django.middleware.security.SecurityMiddleware',
'my_api.middleware.RemoveHeaders'
)
I just had the exact same problem. Your approach with
del response['Server']
Is correct!
However, you need to move your middleware to be the first. As other middlewares will add headers after the response is constructed, so the order of application is bottom-up. Your middleware has to be the first one to have the "last word".

middleware does an infinite redirect

I've already read this but the answer doesnt fit my needs.
I've made this very simple middleware:
class RedirectIfUserIsNotActiveMiddleware(object):
"""
Middleware to redirect if account is disabled
"""
#staticmethod
def process_request(request):
if not request.user.is_active:
try:
# test to see if not already on the right url:
a = resolve(request.path)
if a.url_name != settings.URL_REDIRECT_USER_NOT_ACTIVE:
return HttpResponseRedirect(
reverse_lazy(settings.URL_REDIRECT_USER_NOT_ACTIVE))
# request.path do a 404 if URL unknown -> do nothing :
except Resolver404:
pass
And I've added this here:
MIDDLEWARE_CLASSES = (
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.locale.LocaleMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'django.middleware.security.SecurityMiddleware',
'third_party.hqf_middleware.RedirectIfUserIsNotActiveMiddleware',
)
But when the account is disabled I get an infinite loop with the message on the webbrowser: "mywebsite.com redirected you too many times.".
In my settings I have this:
URL_REDIRECT_USER_NOT_ACTIVE = 'my_home_profile_account_desactivated'
And the URL I'm trying to get is always (even each time step by step) /en/my-home/profile/edit
What am I missing?
It looks as if the my_home_profile_account_desactivated view is redirecting to your login page, and then the middleware redirects back to my_home_profile_account_desactivated, creating a redirect loop.
You should be able to break the authentication loop by changing the middleware so that you only redirect users that are authenticated and inactive.
#staticmethod
def process_request(request):
if request.user.is_authenticated() and not request.user.is_active:
...

Django 'WSGIRequest' object has no attribute 'set_cookie'

I keep on getting this exception when I do request.set_cookie() in the process_view of a custom middleware class. Here is the order of middleware classes in my settings.py:
MIDDLEWARE_CLASSES = (
'django.contrib.sessions.middleware.SessionMiddleware',
'website.middleware.UserLastActiveMiddleware',
'django.middleware.common.CommonMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
)
To start off with, set_cookie() is a method of HttpResponse, not HttpRequest, as you set cookies in your response to a requests.
Secondly, your middleware should come after AuthenticationMiddleware, since presumably it has to do with users.
You should set_cookie() call from response object.
Example:
def process_response(self, request, response):
...
response.set_cookie('user_agreement', user_agreement, domain='.mysite.com')
return response
You can take a look at this question: Django: WSGIRequest' object has no attribute 'user' on some pages?
This problem usually occurs when you do not add the trailing slash because then a redirect is done to the url containing a trailing slash

etag and last modified headers for django app not being set

I am trying to set the etag header using the condition decorator with Django 1.3.
I am using the following:
#condition(etag_func=profile_etag, last_modified_func=profile_last_modified)
#require_person_viewed_is_verified
def profile(request, id):
"""
Return profile for person id.
If profile is not verified only staff and self can view.
"""
user = request.user
...
with a middleware classes of
MIDDLEWARE_CLASSES = (
'django.middleware.cache.UpdateCacheMiddleware',
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'johnny.middleware.LocalStoreClearMiddleware',
'johnny.middleware.QueryCacheMiddleware',
# 'django.middleware.cache.CacheMiddleware',
'django.middleware.http.ConditionalGetMiddleware',
'pybb.middleware.PybbMiddleware',
)
USE_ETAGS = True
I am not getting the etag or last modified headers being set in the http response. Any ideas please?
I was using CharlesProxy (which is a great tool btw) and I had no caching enabled! School boy error I know!