Django caching in authenticated sites: best practices - python

I need to add memcached to my django website.
It's an authenticated website, where different users see different data on the same pages.
Which are the best practices?
I mean, to avoid users to see each other cached pages (information leak)...
I suppose i should use something like:
{% load cache %}
{% cache 500 sidebar request.user.username %}
.. sidebar for logged in user ..
{% endcache %}
or:
#vary_on_cookie
def my_view(request):
# ..
Which is the safest and better way?

It's not the same thing at all, the {% cache %} template tag allows to cache a template fragment and that's used by the server, #vary_on_cookie decorator sets the Vary response header to Cookie, and that's used by the browser.
Also, you could do {% cache 500 sidebar request.user %} instead of specifying the username.

Related

How to delete session variable after use in Django templates

def demo(request):
if data:
request.session['success'] = "Success'
else:
request.session['failed'] = "Failed'
Here I've defined one method and in that if I got data then success session is stored or else failed one.
After that I'm redirecting user to the another page and there I'm displaying this session variable in template.
But after the display of this session status I want to delete that session variable. Because I want to display this message only onetime to user. If user refreshes the page then this variable should be deleted.
I tried to find online but didn't get any help. So please help me with this.
Thank you
P.S: I'm redirecting user to another page using return redirect('page'). Rendering another template using return render(request, "my_tmp.html") doesn't work because that will only load template in current url (URL will not change, only content will). So I don't want that. I know I can use this way by passing session variable in context but that's not I want.
I'm using Django 2
Please do not use session variables for that. Session variables should be used, like the name suggests, for variables that typically have a livespan that is the same as the session. Doing this yourself will also result in a lot of coding, special edge-cases, and likely it will be error-prone.
Django has tooling to show messages to the user: the messages framework [Django-doc]. The documentation specifies how you can set up this framework, although by default it is already installed (so if you did not remove it, there is not much that you need to do).
In your view, you can then add messages, like:
from django.contrib import messages
def demo(request):
if data:
messages.success(request, 'Operation successful')
else:
messages.error(request, 'Operation failed!')
return render(request, 'some_template.html', {})
In your template you can then render the messages like specified in the documentation [Django-doc]:
{% if messages %}
<ul class="messages">
{% for message in messages %}
<li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
You can for example include that in your base.html (and thus extend all other pages from that super template) such that you render the messages on all pages.
Django will automatically clear the messages once these are rendered. So there is no need to do the bookkeeping yourself.

Link to a page in django cms, first check if it exists

I often do things like this in a django template, with django-cms:
{% load cms_tags %}
Imprint
On production, this fails silently, and the href attribute is empty. On development, I'm forced to insert the page with id "imprint", otherwise I get a "DoesNotExist" exception.
How can I improve this situation? Maybe I'm looking for something like
{% if 'imprint'|cms_page_exists %}
...the link and stuff...
Is there a known best practice for this (not quite seldom) use case? Or do you all use it as shown first?
You could assign a tag result to a variable and then check is it empty:
{% page_url 'imprint' as url %}
{% if url %}
Imprint
{% endif %}
Other ways imply creating your own template tag or filters, so the above is the simplest one IMHO.
See also an example in the docs.

Django template check for empty when I have an if inside a for

I have the following code in my template:
{% for req in user.requests_made_set.all %}
{% if not req.is_published %}
{{ req }}
{% endif %}
{% empty %}
No requests
{% endfor %}
If there are some requests but none has the is_published = True then how could I output a message (like "No requests") ?? I'd only like to use Django templates and not do it in my view!
Thanks
Even if this might be possible to achieve in the template, I (and probably many other people) would advise against it. To achieve this, you basically need to find out whether there are any objects in the database matching some criteria. That is certainly not something that belongs into a template.
Templates are intended to be used to define how stuff is displayed. The task you're solving is determining what stuff to display. This definitely belongs in a view and not a template.
If you want to avoid placing it in a view just because you want the information to appear on each page, regardless of the view, consider using a context processor which would add the required information to your template context automatically, or writing a template tag that would solve this for you.

Getting Site_ID in template Django

I have build a web site for a client which has a number of applications. Now he has a new URL registered which he wants to point to the same site, but he wants the look and feel changed. That's basically he wants a new home.html and base.html for the new web site. I can easily add the new site to settings and then change the view for the home page, to display a new home2.html.
However how do I do something like this as expressed in psuedo code in base.html
{% if site_id equals 1 %}
{% include "base1.html" %}
{% endif %}
{% if site_id equals 2 %}
{% include "base2.html" %}
{% endif %}
Any ideas. There are 100s of views on the site and nearly 50 models. I cannot recreate models, and mess around. This needs to be a quick fix.
Thanks in advance
You can create a context processor to automatically add site_id to the context: http://docs.djangoproject.com/en/dev/ref/templates/api/#writing-your-own-context-processors
But I would opt for a different solution. You can simply add an extra template directory per site so Django will try the templates specifically for that site first and fall back to the normal templates if they're not available.
To extend the idea of WoLph with the context processor, I would maybe even add the switching of the template to the context processor which would clean up your templates, as otherwise you may have to repeat the if clause quite often:
from django.contrib.sites.models import Site
def base_template(request):
site = Site.objects.get_current()
template = "base%s.html" % str(site.pk)
return {'BASE_TEMPLATE': template}
And in your template: {% include BASE_TEMPLATE %}
Looks nicer to me than the switching in the templates!
Another solution would be writing a Middleware to set ´request.site´ the current site id.

How do I pass template context information when using HttpResponseRedirect in Django?

I have a form that redirects to the same page after a user enters information (so that they can continue entering information). If the form submission is successful, I'm returning
HttpResponseRedirect(request.path)
which works fine. However, I'd also like to display some messages to the user in this case (e.g., "Your data has been saved" at the top of the screen). If I weren't redirecting, I'd just return these messages in the context dictionary. With the redirect, however, I can't do this.
So how can I pass template context information when using HttpResponseRedirect?
What I'm trying to do seems like it would be incredibly common, so please excuse me if I'm missing something obvious.
For the sake of completion and future reference, you can now use the messages framework. After you install it:
views.py
from django.contrib import messages
def view(request):
# your code
messages.success(request, "Your data has been saved!")
HttpResponseRedirect(request.path)
template.html
{% if messages %}
<ul class="messages">
{% for message in messages %}
<li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
if you are using auth and have a logged in user you could:
http://docs.djangoproject.com/en/dev/topics/auth/#django.contrib.auth.models.User.message_set.create
GET params are also hackable. The querystring, as mentioned in other answers, could be used.
I think the most preferred way would be to use the sessions framework. That way you can load up whatever you want in the context and get
{{ request.session.foo }}
foo could be the message or you could do:
{% ifequal request.session.foo 1 %} Nice work! {% else %} Almost! {% endifequal %}
and other fun stuff.
http://docs.djangoproject.com/en/dev/topics/http/sessions/#using-sessions-in-views
You can't. HttpResponseRedirect sends a client-side redirect (HTTP status code 302) to the browser, and then the browser re-requests another page.
You can set a URL query string on the redirect, though that will be visible to the user and anyone intercepting HTTP requests (i.e. proxies), and is therefore not suitable for sensitive information.
The best way would probably be to use a coded querystring on the redirect URL... its an old school approach.
You could do something like
/page/?m=1, /page/?m=2, etc
You would then parse that variable with request.GET in the view code and show the appropriate message.
From your views.py you hast have to put a key/value-pair into the session and then read it from the HTML template.
For example:
views.py
# your code here
request.session['vote'] = 1
return HttpResponseRedirect(request.path)
your_template.html
{% ifequal request.session.vote 1 %}
<!-- Your action here -->
{% endifequal %}
The only way I know of to pass any data with a redirect is to add GET parameters to the URL you're passing in. To avoid XSS hacks you'd want to pass a specific constant like:
[current path you're passing in]?message=saved
And then process the message=saved parameter in the handler for the path you passed in.
A somewhat more complicated way would be not passing the data in the redirect, and instead using something like http://code.google.com/p/django-notify/ to store session-based data that is displayed to the user following the redirect.
You add ?saved=1 to the query string and check for it with something like:
saved = request.GET.get('saved', False)

Categories

Resources