Django additional arguments to per view cache - django

In the excellent Django cache framework documentation it mentions the possibility of adding additional arguments to template fragment caching:
Sometimes you might want to cache multiple copies of a fragment
depending on some dynamic data that appears inside the fragment. For
example, you might want a separate cached copy of the sidebar used in
the previous example for every user of your site. Do this by passing
additional arguments to the {% cache %} template tag to uniquely
identify the cache fragment:
{% load cache %} {% cache 500 sidebar request.user.username %}
.. sidebar for logged in user .. {% endcache %}
It’s perfectly fine to specify more than one argument to identify the fragment.
Simply pass as many arguments to {% cache %} as you need.
However it doesn't seem to mention anything about doing something similar when the per-view cache. It mentions the possible to use #vary_on_headers and #vary_on_cookie, but that is not quite the same. In my use case I would for example like to use something like request.user.company to ensure all users from the same company get the same cached version of a view.
Is it not possible to add such arguments to the per-view cache instead of defining it in the template?

Related

Change django template search path depending on request

For my application I want to serve a different base.html (and other templates and static files) for visitors and for admins: visitors will see a customized themed frontend, admins will see the editor interface (not related to the django admin interface). Some templates / resources will be shared between the two frontends.
I know I can do this by having separate settings.py configurations and include different template paths in each of them through a django app, but that would also mean I have to run two instances of the app. I'd rather serve both frontends from a single instance (or pool of workers).
Is there a way to dynamically add extra folders to the Django search path? That should suit my needs: if the user comes through the visitor domain, search the added path first and then the defaults, else just use the default template search path.
This is exactly why I've created django_layers
It's inspired by the Plone skinning/layer system where you can switch skins and have the framework search different layers for templates, staticfiles, and so on. I was missing something similar in Django where, like you, the only option I could find was inheritance or distinct INSTALLED_APPS configurations.
It turns out it's also very suitable for other use-cases such as A/B testing.
The packages is relatively new, let me know if it works for you or if you have issues if you decide to use it.
You can leverage template inheritance for this purpose, especially the {% extends %} template tag, which can accept variables instead of literal strings.
Example:
In your child templates make them extend unknown base template like this:
{% extends BASE_SITE_TEMPLATE %}
{% block page_head %}
<!-- Custom per-page static files may be defined here -->
{% endblock %}
{% block page_content %}
...
{% endblock %}
And then write a template context processor that will pass the BASE_SITE_TEMPLATE variable based on your custom conditions to rendered templates:
def base_site_template(request):
# Here goes your conditions to select proper base template, for example
# by checking request.user permissions or some other logic.
...
return {'BASE_SITE_TEMPLATE': ...}
Of course You will need to define various base templates, like base_site_user.html, base_site_editor.html, base_site_admin.html.
This method doesn't require you to change any of your views, just child templates, so I think it's one of the simplest methods to do what You want.

Isn't it rough to retrieve flatpages via get_flatpages template tag from its url instead of a page identifier?

As you can read on the django reference or hacking a bit, get_flatpages can be used as follow:
{% get_flatpages as flatpages %}
{% get_flatpages for someuser as flatpages %}
{% get_flatpages '/about/' as about_pages %}
{% get_flatpages prefix as about_pages %}
{% get_flatpages '/about/' for someuser as about_pages %}
So, if I want to get a specific page I need to do it via its url or a prefix, which is somewhat rough, because my template code become data dependant, I meant, if I change the url of certain flat page then it is necessary to change my template code too.
A more flexible idea would be including an identifier to each page, addable through e.g. the 'Advanced options' section, so that the page can be refered via its identifier, thus we could do something like this:
{% get_flatpages 'about' as about_pages %}
Which is more flexible and less data dependant, no matter what url the page has, note we could change the page's url without changing the template code.
Is there something like that in the framework?, of course I could customize this app or to use a third-party app, but this isn't the point ;-)
Have you any other idea to deal with?
No, I don't believe there's any support for what you're asking for in Django at present. The docs you linked to for flatpages say:
A flatpage is a simple object with a URL, title and content. Use it for one-off, special-case pages, such as “About” or “Privacy Policy” pages, that you want to store in a database but for which you don’t want to develop a custom Django application.
My reading of this is "this is the bare minimum we're providing, and if you want any more you'll have to code it yourself". I agree that your proposal of allowing pages to be referred to by a symbolic name (which perhaps defaults to their URL) is more flexible, but you're probably better off raising an issue for it or discussing on the mailing list than hoping a dev happens upon your question on StackOverflow.
In the short term, you could look at some of the pre-built CMS-like Django apps. Django-page-cms is relatively lightweight (it's a relatively small app itself but does have a bunch of dependencies) and you could accomplish what you're after: each page is referred to by its slug (aka url / name), but you can define aliases / redirects to given pages for arbitrary URLs.

reading and caching html fragment for use on django template

I need to grab four html fragments from an external web site and display them within my django site's header and footer. I definitely need to cache these for some period of time.
My initial thought was to use urllib2 to read the http and then write the html to files to my server. Implemented through a Django context processor, the code checks the timestamps of the four files and retrieves updated versions if necessary before reading them into template variables.
I appear to be maxing out Django's template variable size for one of the four files. This forced me to use readlines() and to pass that file into the template as an array.
Is there a more elegant way to retrieve four html fragments from an external site, cache them and pass them to my templates?
Here's what my base.html template looks like now:
{{ integration_prehead|safe }}
<head>
{{integration_head|safe }}
...
</head>
{% for l in integration_topper %}{{ l|safe }}{% endfor %}
{{ block content }}{{ endblock content }}
{{ integration_footer|safe }}
The prehead.html isn't much of anything other than the doctype and opening html tag. The head.html is a bunch of javascript and stylesheets. The topper.html and the footer.html are the biggest pieces and they're the top and bottom of the pages. The topper, in particular, can change every 15 minutes so it's not practical to hard-code it on my templates.
Topper is 39k and too big to read into a single Django template variable, hence the for loop.
If you have any control over the server you're pulling the fragments from, your best bet is to set up dedicated views that return just the fragments and not the entire HTML document.
You can then use Django views to either manually save the fragments to disk or use Django's Cache framework. The cache framework will be much more robust and provide additional means of storage such as via database or memcached, but it's not guaranteed to store the fragment for a defined period of time. For example, memcached will lose everything if the server has to be restarted.
If the source server is not in your control, I'd highly recommend that you run the document through an HTML parser first, and pull out and pass in to your template only the pieces that your need. BeautifulSoup is a nice one for python.

How to load objects from model on server start up?

I store my sites navigation menu in database. I want to load all objects in the list once I launch my server, but I haven’t got idea how to do it. I really need to do it, because it will be problem in future to load data from database in views to display menu.
I tried to put loading code in settings.py, but there was an error, and in views after imports, but there was no effect.
I think you need Template context processors.
Here is a nice tutorial by James Bennett on that:
http://www.b-list.org/weblog/2006/jun/14/django-tips-template-context-processors/
Well, I'm very new to django, and maybe I'm wrong, but I think you are looking for something like caching. Read the docs, and decide whether is it fits you or not.
You can cache just a part of your view:
https://docs.djangoproject.com/en/1.3/topics/cache/#template-fragment-caching
surround your navigation bar like this:
{% cache 500 navbar %}
... put your navbar code
{% endcache %}
and ensure to have
{% load cache %}
at the top of your template or the base template.

CMS subsites with Django

I'm using Django to create a site that provides a separate web UI for sorts of producers and consumers. Both UIs (or "subsites") have different layouts, menus and graphics. However they access the same database and models, just from different aspects (producer vs. consumer...).It's all hosted under a single domain, the UI differentiation is done with URLs.
The problem comes when I want to integrate a CMS to this system, to take care of the menu structures and textual content. How should I go about handling the two different menus for the different UIs? I took a look at django-cms and django-page-cms, and they seem to maintain only a single menu hierarchy.
Any ideas?
One dirtyish solution would be to add e.g. a different prefix for each UI's menu items in the CMS, and hack the CMS code so that it only inserts the menu items for the correct UI (given as a parameter to the show_menu template tag).
A nicer way would be if it was possible to have multiple instances of the CMS app, so that each of them had their own database tables as well. But is this possible with django and e.g. django-cms or django-page-cms?
Some further restrictions:
the CMS must support localization
I'd prefer running a single Django instance, to keep the configuration and testing simple
I have not used django-cms so this is just off the top of my head.
There's a section of the docs called Extending the menu that looked promising. It may be unfortunate that so much of their configuration is in settings.py because it looks like you could manipulate their CMS_TEMPLATES to use different base templates (etc.) for different users. One way of getting around this (assuming that there is not a more direct route) is to add something to the UserProfile that identifies a user as consumer/producer. Then in your base.html you do:
{% if user.get_profile.consumer %}
...
{% else %}
...
{% endif %}
This effectively gives you two entirely different look/feel options based on user type. I'll also note that {% extends %} can take either a string constant or a string variable, so you could use a context_processor to set the name of template you are extending.
What you need is show_menu_below_id tag of django-cms. Create the pages consumers and producers with their respective id (advanced fieldset, on bottom of the page form) and then start building the page hierarchy for each one.
Then in the templates uses the tags:
<ul>
{% if user.get_profile.consumer %}
{% show_menu_below_id "consumer" %}
{% else %}
{% show_menu_below_id "provider" %}
{% endif %}
</ul>