Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django - two views, one page

Say we have a Django page that shows a list of items and allows the user to fill in a form to add to the items (let's call the items posts).

What I want: The URL for this page refers to a view. The view calls two other views (called "sub-view" hereon), then each sub-view renders its section and returns the results. The main view then joins the results of the sub-views and returns that.

Ideally, I would have a quick javascript check on the page - if javascript is enabled, the submit button for the form will be "Ajax'd" to the sub-view that deals with form adding, and the page will be updated that way. I suppose I could trigger a request to refresh the list of posts afterwards too or something.

So how do I concatenate the two sub-views in the main view? Is this possible?

UPDATE: "sub-view" is a term I made up. What I want is a view that can be called either by Ajax directly to return something meaningful, or from another view (which I'll call the "main view"). If called by this "main view", how does the main view handle returning the data from multiple "sub-views"?

Is there a simple way to do this? Is this an appropriate way to think about multiple views in a page? Should I care about separation of responsibilities?

like image 679
bharal Avatar asked May 15 '12 20:05

bharal


3 Answers

A view in django is just any callable that ultimately returns a Response object. Within that view, you could split the work up into whatever organization suits you. Maybe your view 100% delegates out to other methods.

In your case, your main view would call 2 other functions for data. These could also be views if they also accept a Request object as well and make use of it. They also would need to return Response objects to be considered django views since that is how you would point URLs at them. But it doesn't really do you any good to have two other views returning you Response objects. What you probably want is just other methods that do specific tasks and return some data structure, or maybe even a rendered snippet of a template. You would then use these data, or merge the template strings together and return that in your main Response.

If you are really set on making use of other views that return Response objects, then you can do something like grabbing the body out of them, and merging them into your own response:
https://docs.djangoproject.com/en/1.4/ref/request-response/

Really, nothing is much different from the tutorials. You are just calling other methods for data. If you want to make it organized you should separate the data processing logic from the view function. Your main view would call these data processing functions for values. And your "sub views" would just be simple views that also call these individual data functions and wrap them into a Response.

Pseudo:

def mainView(request):
    val = data1()
    val2 = data2()
    response = # val + va2 + other stuff
    return response

def subView1(request):
    val = data1()
    response = # val  + stuff
    return response 

def subView2(request):
    val2 = data2()
    response = # val2  + stuff
    return response 

def data1():
    val = # get data
    return val 

def data2():
    val2 = # get data
    return val2
like image 138
jdi Avatar answered Nov 14 '22 19:11

jdi


The views should contain only view-related logic:

  • Views are for processing requests and serving the requested data
  • That includes checking for user authorization/permission and dealing with given parameters
  • If the requested data is not trivial to fetch, outsource the code to a more appropriate location (your model or form definitions or another custom place)

Outsource calculations to make them reusable and call these methods from your views to keep them small.

Nevertheless, maybe you want something else, namely templates with extends and include.

With extends you are able to create a base layout for your HTML code and define specific blocks which can be rendered elsewhere. Example? Ok.

base.html:

<!doctype html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <title>{% block title %}My Site{% endblock %}</title>
    </head>
    <body>
        <div id="header">
            <h1>My Site</h1>
        </div>
        {% block content %}{% endblock %}
    </body>
</html>

Then, in any other template, you can overwrite the blocks title and content which we defined in the base template:

{% extends "base.html" %}

{% block title %}My Page{% endblock %}

{% block content %}
<h2>My Page</h2>
<div>lorem ipsum</div>
{% endblock %}

Also, you can create sub-templates like the following one, let's name it _item.html:

<li class="item">
  <span>{{ something.foo }}</span>
  <strong>{{ something.bar }}</span>
</li>

You can include that snippet in any other template and pass an arbitrary number of parameters:

{% for something in mymodel.mym2mrelation.all %}
    {% include "_item.html" with something=something only %}
{% endfor %}

Naturally, you can combine both concepts. Like so:

{% extends "base.html" %}

{% block title %}My Page{% endblock %}

{% block content %}
<h2>My Page</h2>
<div>lorem ipsum</div>
<ul>
{% for something in mymodel.mym2mrelation.all %}
    {% include "_item.html" with something=something only %}
{% endfor %}
</ul>
{% endblock %}

I hope that helps.

like image 40
Alp Avatar answered Nov 14 '22 20:11

Alp


This is the perfect time to introduce class based views.

class methods are essentially "sub views" that split logic into reusable snippets.

If you want the readability of split functions - it only gets better by using django's class based views (via all of the functionality provided by default and access to request, kwargs, args, etc., via the class instance).

The docs even contain a good example for returning a JSON response or HTML response based on request parameters (this exact situation).

The best part? You can reuse your class based views as mixins in future views. Look at the docs example to see how to convert any class based view to handle a JSON response of the template context via a simple subclass.

like image 45
Yuji 'Tomita' Tomita Avatar answered Nov 14 '22 19:11

Yuji 'Tomita' Tomita