Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django: How do I update a model after a view has been rendered?

I have a view that displays a list of models. Some of the properties of some of the models need to be updated after the view has been rendered: that is, the user is expected to see the original, unchanged values on first visit and the updated values on successive visits (or upon page reload).

I thought I could achieve this with class-based generic views. The official documentation hints at "doing some extra work before or after calling the generic view" (emphasis mine), but all examples given affect the models before it is displayed.

I looked into signals, but to no avail.

Spawning an asynchronous task is an option, but, since all I need to do is update a field in a few models (likely one or none) and save them, it seems overkill for the task at hand.

One could use an ajax request to trigger the update, or a custom template tag to display the relevant fields and update them thereafter. I dislike both, as they move application logic into the view layer. The ajax technique also adds the overhead of a second request.

Yet, I seem to have no other choices, or do I? Is there a more practical technique for plugging into the generic view or the request and execute extra logic after the template has been rendered?

like image 691
tawmas Avatar asked May 31 '11 21:05

tawmas


1 Answers

There's no need for anything clever here. Rendering a template doesn't need to be the end of the view - that only comes when you actually return that as a response. They don't have to be in the same step.

So :

def my_view(request, params):
    #...do something...
    response = render_to_response('my_template.html', {'foo': bar})
    # ...do something after rendering...
    return response

Now, if you need to do this in a lot of views, you might want to do it in a decorator:

def my_decorator(view):
    def my_func(request, params):
        response = view(request, params)
        #...do something after rendering...
        return response
    return my_func

now you can decorate your views with @my_decorator and the action will be performed after rendering.

... or, it just occurred to me, if you want to do it in every view, you could do it in a middleware (just define the process-response method).

Edit after comment Class-based generic views use the new TemplateResponse class. You can add tasks that happen after the template is actually rendered with a post-render callback.

like image 66
Daniel Roseman Avatar answered Oct 21 '22 17:10

Daniel Roseman