I would like to put Varnish as a in front of a corporate website built with Django, to improve its performance. On every single page of the site there is a small contact us form. Other than that, the site is mostly static. The trouble is I can't figure out how to combine Varnish with Djangos Csrf protection. I suppose the same question applies to any sort of full-page caching with the Django csrf protection.
I suppose turning off the csrf middleware is a no-no - right?
matti
Normally I would suggest you to start using Django + Varnish ESI.
In case if you use only full page caching - I suggest you the following workaround:
Move forms loading to AJAX call (to POST request)
In your vcl file either mark only GET requests for lookup or mark POST requests for hit_for_pass.
Related
I have a backbone.js single-page app that is all set up with the router (well, actually a Backbone.Marionette app with a Backbone.Marionette AppRouter, but nevertheless). However, the backend is based in Django, where I do not have the URL conf directing to views for all URLs that are already in the backbone.js routes.
Based on the existing URLs in the Django URL conf, Backbone.js will serve the backbone routes regardless of what is listed in the Django conf - it seems something, anything just needs to be there.
Do I need to have proper Django views in order to offer a fallback for older browsers/SEO?
What are the best practices to coordinate the Django URL conf and the Backbone.js Router?
I've found a post that addresses this issue quite well:
http://duganchen.ca/single-page-web-app-architecture-done-right/
Briefly, my reasoning for including a fallback is for non-javascript browsers and SEO reasons. At the time of this post, non-javascript browsers account for ~1.4% (less than 2% from everything I've read) of users, making SEO The major consideration. Again, SEO may not be relevant for everyone reading this post, in which case, this can be skipped.
I found Thomas Davis' tutorial using phantom.js quite helpful. http://backbonetutorials.com/seo-for-single-page-apps/
However, another issue that I needed to account for was the history API, which has been neglected by all but the latest IE browsers. Given my client's users, about 15% of which are using IE <= 9, this was also a problem.
In the end, I also needed to use history.js. All in all, this was a lot of work to update an otherwise very simple website. However, I learned a lot from this ordeal.
In my opinion if your backbone app is truly a single page then you don't need any django views whatsoever. You can serve your index.html as a static file (in production, not even by django) and then let backbone's router take care of your url configuration, as you're doing already. You can use backbone's history and navigate to fake urls, add urls parameters etc, for resources in your app.
I'm experimenting with various Django 1.3 caching approaches to use for our landing page. This page has results from several database queries as well as user authentication. By far the best-performing solution has been to use the #cache_page decorator to cache the whole view function response. The problem is that user auth also gets cached.
I can create a key in the cache for each user but this seems wasteful; caching the same landing page over and over with the only difference being the user's authentication. I also used template fragment caching and low-level caching for all but the authentication but the performance was nowhere near as good as the #cache_page decorator approach.
Is there a way to get the performance of #cache_page without lots of redundant user-based caching?
Check out this blog post: http://www.holovaty.com/writing/django-two-phased-rendering/
Basically the technique is to wrap your user-specific segments in a template tag that prevents the template engine from rendering them, then cache, and then re-render the cached output to fill out the user details.
Django 1.5 includes a tag called verbatim which can be used instead of the custom raw tag in the post; you'll still need the custom CachedTemplateMiddleware or equivalent though.
I have a login form on my homepage. This is causing a csrf token to be set and this is meaning that my page is not being stored in the varnish cache.
How should I get around this?
You have two main courses: either give up using varnish to cache the page, or give up having a login form on the page. The CSRF token (which you don't want to lose) will prevent you from successfully caching the page in varnish; even if you take it into account, you're going to end up with a copy of the page for every single person visiting, which defeats the purpose of using varnish.
A solution halfway between the two is to cache the page without login form in varnish, and then insert the login form using Javascript. The main page will be cached, and you should be able to make the login form (pulled via AJAX) fast enough to not cause you problems. Another possible solution would involve putting the login form in an IFRAME, although that complicates matters yet further since you'd have to have something in the response to logging in which worked with Javascript in the main page (that included the IFRAME in the first place) to reload it suitably.
I’m using Django version 1.3 alpha 1 (SVN-14750) to build a Django site.
I’ve got a couple of pages which display data, and allow me to edit that data. However, I seem to have to restart the built-in Django web server to see the updated data.
I don’t remember having this problem before: usually a CTRL + F5 refresh in the browser would do it. Obviously, it’s quite annoying behaviour during development, seeing up-to-date data load slower is preferable to seeing out-of-date data load instantly.
I’m using Firefox with the cache disabled (about:config, network.http.use-cache=False), so I’m reasonably sure the issue is with Django.
Web servers themselves don't do caching. It is up to the application itself to decide how (server-side) caching works. In Django's case, there are a number of options for enabling caching.
The high level though, is that Django sees a request for an URL, generates the html string in response, and stores that string in memory (or a database - depending on the cache backend you set). The next time a request comes through for that same URL, Django will check to see if that response lives in the cache, and if it does, will return that string. If it doesn't, the process repeats.
The idea behind providing #vary_on decorators, is that you change the lookup keys for finding a response in the cache. If you vary_on(user, url). the algorithm goes something like this:
1. request /users/3/Josh
2. key = str(user) + str(url)
3. response = get_from_cache(key)
4. if response is None: response = view_function()
5. save_to_cache(key, response)
6. return response
The web server has no input into this type of caching.
The other type of caching is client side. This is where the web server is configured to return certain headers for specific types of resources like static content (javascript, images etc). The browser can then analyze those headers, and decide to request the content, or to use the content stored client side. This generally doesn't apply to dynamic content however.
Ah — I still had some cache middleware enabled. Removing the following from my MIDDLEWARE_CLASSES setting in settings.py fixed it.
'django.middleware.cache.UpdateCacheMiddleware',
'django.middleware.cache.FetchFromCacheMiddleware',
(As is probably evident from the question and this answer, I don’t understand caching, Django or otherwise, very well.)
Maybe it's a stupid question, but I'm trying to login to my django app using a form that is outside django. My guess is that I could send a POST request to /login, but that would fail because of the csrf token.
Maybe I'm missing some kind of theoretical background, but I would like to know what's the correct way to achieve this.
Background info:
The django authentication is working fine IF you use the django login forms. What I'd like to do is to use an external static html form (on an apache outside django), to post to django directly so when I redirect to my django server, I don't have to login.
CSRF exists to prevent exactly this. Although you no doubt have good intentions, there's no technical difference between this and a hacker trying to steal access to your site via a real CSRF attack.
Sounds like you need a single-signon service like CAS: http://code.google.com/p/django-cas/
(but it's possible overkill)