Django Caching for a Blog - django

I have a blog written in Django, and I started using the basic Django caching middleware with the file system caching backend. Unfortunately, this led to two things being cached that shouldn't have been: admin links (e.g. "Edit this post") for logged-in users and
prepopulated comment forms based on cookies.
To get around that, I started using the template cache tags:
{% load cache %}
...admin links...
{% cache 500 blog_entry entry.id %}
...entry...
{% endcache %}
...comment form...
But it seemed that the whole page was still getting cached as well. How do you set up the caching system to only cache the parts of the template you explicitly set?
Edit: For the comments, if someone comments on the blog, I store their name, website, and email address in the session variables. If they come back to the site, then I prepopulate those parts of the form with that data. But that means it is possible for the caching system to cache a view with prepopulated data, which is not good.

You need to remove the caching middleware now that you are caching template fragments instead of entire pages.

Add this to your settings.py:
CACHE_MIDDLEWARE_ANONYMOUS_ONLY = True
This should fix the issue with admin links, I don't quite understand what your second issue (prepopulated comments) is?

Related

Django Wagtail pageurl template tag returning incorrect host name

I'm using Wagtail 1.8 and the pageurl template tag on a blog index page to hyperlink the titles of the blogs through to the actual blog pages. Pretty standard stuff. This is a Django 1.10 project.
<a class="blog-post-link" href="{% pageurl blog %}">
<h2>{{ blog.title }}</h2>
</a>
The very strange problem I'm having is that the host name of the site is being replaced by the host name of my server that is hosting the site. For example, a correct link would be:
https://beadtrails.com/blog/vernon-bc-what-to-do-on-and-off-the-trails/
However, it is sometime being returned as https://graphicearth.ca/blog/vernon-bc-what-to-do-on-and-off-the-trails/
When I say sometimes, if I go to the wagtail admin sites page, then into the host record and save it, it will fix the problem--for a while. It will then revert back to the incorrect url.
As you can imagine, this is not a great situation where your blog links end in a 404 error!
For trouble shooting, I've checked the config of both Wagtail and Django sites tables, checked the config files correctly identify the SITE_ID, done a text search through all the source code for 'graphicearth.ca', reviewed the uWSGI and nginx config files, checked that the blog hierarchy is correct within Wagtail relative to the home page, checked the headers in the browser to make sure the right host is being passed. Everything looks ok.
Digging into the source code for the template tag, which is in wagtailcore_tags.py, the comments for the function says:
Outputs a page's URL as relative (/foo/bar/) if it's within the same
site as the current page, or absolute (http://example.com/foo/bar/) if
not.
So for some reason, the code ends up thinking that the sites are different--but not all the time. As mentioned above, if I go into the Wagtail admin and re-save the sites entry it fixes things for a while.
As this is on a production system, it's rather hard to debug. Does anyone have any suggestions on what might be causing this and/or how to debug it?
Application stack is:
- Django 1.10.5
- Wagtail 1.8
- uWSGI
- nginx
Answer update:
Tom's response was what led me to find the solution so I've marked his answer as correct. I was using the same memcached instance for multiple sites and the keys must of been getting crossed. I reverted to basic django cache and it resolved the problem. Time to find a better solution for caching with multiple sites on the same server.
Do you have a cache configured on the production system? The pageurl template tag calls get_site_root_paths() which uses a cache of site root paths if one is available. The cache should be purged if sites are edited or deleted, but perhaps you could try configuring settings.CACHES to use DummyCache to help track down the issue.

django-mobile views rendered to the desktop & vice-versa when using caching

I've got a project running Django CMS and django-mobile for rendering different templates to mobile defines.
With page caching enabled in Django CMS it's possible to see the full mobile template displayed on a desktop browser or the other way around; desktop on mobile.
From some Google docs, I believed the resolution to this was setting middleware for patch_vary_headers;
from django.utils.cache import patch_vary_headers
class VaryHeaderMiddleware(object):
def process_response(self, request, response):
# Set Vary Header based on
# https://developers.google.com/webmasters/smartphone-sites/details
patch_vary_headers(response, ['User-Agent'])
return response
With the CMS_PAGE_CACHE disabled I've not seen full page templates rendered to the wrong devices, but I have got a page which as rendered with the desktop template, but then the apps rendered to the page through CMS placeholders have rendered their mobile template to the desktop. And this is while CMS_PLACEHOLDER_CACHE and CMS_PLUGIN_CACHE are still enabled.
Now I've just found this bug report from Django that suggests it's possible to omit the vary header when using the page caching decorator, but can this happen at a broader scale if I'm seeing mis-matched template rendering while certain elements are being cached?
I'm running the latest django-mobile 0.5.0 and I believe all middleware classes are defined in the correct order;
'project.middleware.VaryHeaderMiddleware',
'django_mobile.middleware.MobileDetectionMiddleware',
'django_mobile.middleware.SetFlavourMiddleware',
'django_mobile.cache.middleware.CacheFlavourMiddleware',
'django.middleware.cache.FetchFromCacheMiddleware',
)
When the CMS_PAGE_CACHE fails to distinguish mobile from desktop devices, it's OK to switch it off and to replace it by Template fragment caching, see the docs.
The easiest way would be to start your base template with e.g.
{% load cache %}
{% cache 500 the_whole_page %}
and to end it with
{% endcache %}
I havn't tested it, but it should work.

django memcached optimalization

I am deploying social networking site with django on VPS, my current stack is nginx, postgresql, gunicorn. I am going to add memcached, I will be forced to use {% cache %} tag in my templates or low level api in views though, as each site will be dynamic for authenticated users. I have 1 question regarding {% cache %} tag, lets say i will input a variable within cache tag like so:
{% cache 500 x %}
{{ variable }}
{% endcache %}
Lets assume that {{ variable }} is in fact very consuming database query written in related view. What would be the best way to prevent database hit from view (lets assume query will be evaluated in view) , should i cache it as well with low level api? If so isnt it a bit redundant as I would cache it in both places? Please give me your thoughs what would be the most convenient method. Btw, I know that this example is trivial, if I only wanted to cache variable I could do this in view, but I will surely need to use cache tag to cache some loops, multiple html lines generated by python etc. Thanks
First, the usage of authentication in your site doesn't involve the usage of low level cache in both sides views and templates, note for instance you can do something like {% cache 500 user %} and that will save different chunk of code of each user of your site.
Answering your second question: in general, you can prevent database hits just caching into the templates. Evaluate the query there instead of doing into the view, and make a dynamic clean up of the keys when the content changes instead of using fixed expiration times, that way let you get better performance result. Also, take in mind cache tag saves just chunk of HTML code.

partly caching a view method

I am using Memcached (with python-memcached binding) with one of my django projects. The scenario is that on the homepage i have:
A Top Bar : (This contains the links to login / User name with a link to the profile)
A Search Form
Few Blocks Of Results
Currently, I am using the cache_page() decorator to cache the whole page as follows:
#cache_page(3600)
def home(request):
# View Code Goes Here
and the above is working as expected. But as the homepage is a publicly accessible page i am facing a problem with one scenario where:
An anonymous user request the home page(the page get's cached if it
is not already).
Now the user logs in and is redirected to the homepage.
The cached homepage loads (Topbar still shows a login link instead of the logged in user's Name and profile link as the page was cached before the user logged in.)
Question:
Is there a way either on template level or on view level, that lets us specify a block we DO NOT want to cache while using cache_page() decorator ?
Please Note: I am aware that we can use {% cache %} template tag or cache.set for each block in the above scenario. But i am specifically looking for a solution where we can use the cache_page() decorator and still be able to specify a block that i do not want cached in a particular view or a template
use CACHE_MIDDLEWARE_ANONYMOUS_ONLY
yet it sounds as a middleware option, it affects #cache_page as well

memcached caches request?

after caching several views on my django project -#cache_page(60 * 5)- I've noticed that memcached caches the entire view, even the request argument! So if the first user that visits a page is logged in as userxyz, all other anonymous or registered users that will ask the same page will be presented with the page that was cached by user userxyz! Obviously this is not a desired behavior...So can I cache everything on the view, but not the request argument? Or memcached is suitable for anonymous sessions only?
Thanks in advance,
Markos Gogoulos
If you're mixing dynamic and static data on one page, in your case the dynamic data is the logged in user's username, then page caching isn't the right choice. This wouldn't change if you were using file based cache storage instead of memcached.
I suggest trying fragment caching. You can do something like this:
{% load cache %}
{% cache 500 sidebar %}
.. sidebar ..
{% endcache %}
This will cache the contents of the cache tag for 500 seconds with the identifier sidebar.
You can find more information on caching here:
http://docs.djangoproject.com/en/dev/topics/cache/
If this is a page that is going to be hit very often, for example a welcome page, that you feel would benefit from using page caching over fragment caching (for example the only dynamic data is the user name), then there are a few other options.
Say for example you want to have a completely static page except for a login/logout section at the top which displays different links depending on whether or not the user is logged in then you can check for the existence of an authentication cookie when the page is first loaded and conditionally display different data using javascript.
Memcached is just a backend. It caches whatever you tell it to cache. So really your question is "Is Django's full-page caching suitable for dynamic pages?"
Probably you don't want do cache full-pages, just part's of it. Or only pages for anonymous requests (using CACHE_MIDDLEWARE_ANONYMOUS_ONLY)
Refer to the book
http://www.djangobook.com/en/1.0/chapter13/
You might want to look into template fragments and caching those bits of content that aren't user specific.