tags:

views:

2048

answers:

3

Alright, this is probably a really silly question but I am new to Python/Django so I can't really wrap my head around its scoping concepts just yet. Right now I am writing a middleware class to handle some stuff, and I want to set 'global' variables that my views and templates can access. What is the "right" way of doing this? I considered doing something like this:

middleware.py

from django.conf import settings

class BeforeFilter(object):
    def process_request(self, request):
        settings.my_var = 'Hello World'
        return None

views.py

from django.conf import settings
from django.http import HttpResponse

def myview(request):
    return HttpResponse(settings.my_var)

Although this works, I am not sure if it is the "Django way" or the "Python way" of doing this.

So, my questions are:
1. Is this the right way?
2. If it is the right way, what is the right way of adding variables that can be used in the actual template from the middleware? Say I want to evaluate something and I want to set a variable headername as 'My Site Name' in the middleware, and I want to be able to do {{ headername }} in all templates. Doing it the way I have it now I'd have to add headername to the context inside every view. Is there anyway to bypass this? I am thinking something along the lines of CakePHP's $this->set('headername','My Site Name');
3. I am using the middleware class as an equivalent of CakePHP's beforeFilter that runs before every view (or controller in CakePHP) is called. Is this the right way of doing this?
4. Completely unrelated but it is a small question, what is a nice way of printing out the contents of a variable to the browser ala print_r? Say I want to see all the stuff inside the request that is passed into the view? Is pprint the answer?

+4  A: 

1) If you modify 'settings', this is truly going to be global even across requests. In other words, concurrent requests are going to stomp each other if you need each request to have its own value. It's safer to modify the request object itself, which is what some of the common Django middleware does (e.g. django.contrib.auth.middleware.AuthenticationMiddleware adds a reference to 'user' on the request object)

2) (EDIT 2) See #4, getting a common set of variables into each template is probably better suited for a custom context processor

3) I'm not familiar with CakePHP, but adding a process_request middleware is definitely a good Django way of preprocessing each request.

4) Take a look at the doc for template context processors. If you use RequestContext each template will have a context variable called 'request' that you can dump to your template. You can also use the debug context processor and do something like this so it only dumps when settings.DEBUG=True:

{% if debug %}
  <!-- {{ request.REQUEST }} -->
{% endif %}

This will work for both GET and POST, but you can modify accordingly if you only need one or the other.

EDIT

Also, I just looked closer at your views.py. Not sure I fully understand what you are trying to do there by just returning the variable in the response. If you really have that use case, you'll probably also want to set the mimetype like this:

return HttpResponse (..., mimetype='text/plain')

That's just to be explicit that you're not returning HTML, XML or some other structured content type.

EDIT 2

Just saw the question was updated with a new subquestion, renumbered answers

Joe Holloway
+1, Thanks for your help. The view was just an example I will have templates and all that good stuff it's just what I was using to test that the variable was getting there and all but yeah. Thanks again.
Paolo Bergantino
+9  A: 

Here's what we do. We use a context processor like this...

def context_myApp_settings(request):
    """Insert some additional information into the template context
    from the settings.
    Specifically, the LOGOUT_URL, MEDIA_URL and BADGES settings.
    """
    from django.conf import settings
    additions = {
        'MEDIA_URL': settings.MEDIA_URL,
        'LOGOUT_URL': settings.LOGOUT_URL,
        'BADGES': settings.BADGES,
        'DJANGO_ROOT': request.META['SCRIPT_NAME'],
    }
    return additions

Here the setting that activates this.

TEMPLATE_CONTEXT_PROCESSORS = (
    "django.core.context_processors.auth",
    "django.core.context_processors.debug",
    "django.core.context_processors.i18n",
    "django.core.context_processors.media",
    "django.core.context_processors.request",
    "myapp. context_myApp_settings",
    )

This provides "global" information in the context of each template that gets rendered. This is the standard Django solution. See http://docs.djangoproject.com/en/dev/ref/templates/api/#ref-templates-api for more information on context processors.


"what is a nice way of printing out the contents of a variable to the browser ala print_r?"

In the view? You can provide a pprint.pformat string to a template to be rendered for debugging purposes.

In the log? You have to use Python's logging module and send stuff to a separate log file. The use of simple print statements to write stuff to the log doesn't work wonderfully consistently for all Django implementations (mod_python, for example, loses all the stdout and stderr stuff.)

S.Lott
+1 Thanks for your help. I can't seem to find TEMPLATE_CONTEXT_PROCESSORS in my settings.py... do I have to add it?
Paolo Bergantino
@Paolo Bergantino: Interesting. Most folks have it by default. See http://docs.djangoproject.com/en/dev/topics/settings/#topics-settings
S.Lott
If you create the project using "django-admin startproject" then the TEMPLATE_CONTEXT_PROCESSORS won't be in the newly created settings.py. When it's missing the global_settings value will be used of course, which for Django 1.02 is just auth, debug, i18n, and media.
Van Gale
+16  A: 
  1. It's not the best way. You could set my_var on the request rather than on the settings. Settings are global and apply to the whole site. You don't want to modify it for every request. There could be concurrency issues with multiple request updating/reading the variable at the same time.

  2. To access request.my_var in your templates you could do {{ request.my_var }}. To get access to the request variable in your template you will have to add django.core.context_processors.request to your TEMPLATE_CONTEXT_PROCESSORS setting.

  3. Yes. Other terminology to describe request middleware would be request pre-processor/filter/interceptor.

Also, if you want to use a common Site name for the header in your templates, you might want to check out the Django Sites application which provides a site name variable for your use.

Akbar ibrahim
+1 This is exactly what we do with one exception: we add a dict to the request and then add values to that. This keeps you from "polluting" the request's namespace any more than necessary.
Peter Rowell
+1 Thanks. The Site Name was just the first example I thought of when writing the question, my use case is for something else.
Paolo Bergantino