3

I would like almost every View in my Django project to compute, for instance, time_on_mars. This variable needs to be put into every template context, so every template can draw time_on_mars. I'd also like every View to be able to use that variable if it wishes, maybe to compute is_it_nighttime_on_mars or whatever. I'd like to do this using inheritance, or some other mechanism, so when I provision a whole lot more than mars time, I don't repeat myself.

Is this an appropriate use of class-based Views? I guess I'd create a base class view, and in its get and post methods, calculate the current time on mars, then call child class methods 'doGet' or 'doPost', intercept the result, put the mars time into the result, and continue. Seems tedious.

Decorators? Is there a way I can put time_on_mars into the closure context for the view?

What's the pythonic (djangonic?) way to do this?

EDIT: I like the idea of context processors, but I've changed my mind - instead of every view, I'd like most views to get this. Especially if it's expensive to compute the time on mars...

EDIT 2: Problem description not adequate! To clarify:

I have a bunch of views that do this:

def some_view(request):
   w,x,y,z = provision_wxyz()
   ... some biz logic, maybe compute a,b,c using w,x,y,z ...
   return render(request, 'some_template.html', { 'a':a, 'b':b, 'c':c, 'w':w, 'x':x, 'y':y, 'z':z })

... and I'd like to abstract out the first step (w,x,y,z=), and the adding of w,x,y,z to the template context. Context processors don't work, because inside the some_view business logic, I want access to w,x,y,z. I don't like doing the mixing strategy for CLA on the TemplateView, because again, it doesn't give me access to w,x,y and z inside some_view (or whatever the equivalent of some_view is), and I want to, well, do a bunch of business logic somewhere, and TemplateView doesn't seem to give me that?

5
  • 4
    This is a job for context processors. Commented Sep 8, 2015 at 19:47
  • Can I use the variables that my custom request context makes in my view itself (not only the template)? Commented Sep 8, 2015 at 20:28
  • 1
    No. If you want it there, a custom base class (or mixin) is your best bet. Commented Sep 8, 2015 at 20:36
  • A class-based view also doesn't do the trick - how can I make sure all sub-classes add appropriate variables to the render context? This is unbelievable, I must be missing something. Commented Sep 8, 2015 at 21:17
  • I don't understand why it's not a solution. You ensure that by defining get_context_data in your class which adds your value to the dictionary created by the super class. Commented Sep 8, 2015 at 21:36

2 Answers 2

2

You can definitely use CBV's for this. It is a great use for Mixins which take advantage of pythons multiple inheritance. Here is a quick and dirty example I just wrote out.

class MarsMixin(object):
    time_on_mars = 5

    def get_time_on_mars(self):
        """
        Does what it takes to return a time on mars be it calculation
        or returning a property set on the object. Should return a property
        from the object if it is a constant. Should calcualte in the method
        if it is going to be dynanic
        """
        return self.time_on_mars

    def get_context_data(self, **kwargs):
        context = super(MarsMixin, self).get_context_data(**kwargs)
        context['time_on_mars'] = self.get_time_on_mars()
        return context


class HomeView(MarsMixin, TemplateView):
    template_name = 'home/index.html'

Biggest notes are the mixin inherits from object. The other is you inherit from mixin in the HomeView and it is listed before the TemplateView.

Sign up to request clarification or add additional context in comments.

Comments

1

I think you can still use context processors, the tip that can help is to prefix the urls where you want to do your calculation, for example they will start by '/mars/...'. You can also use another kind of prefix.

Like this you can check on the context processor method:

def go_to_mars(request):
    if request.path.startswith('/mars/'):
        return {'time_on_mars': calculate_time_on_mars()}
    return {}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.