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?
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
The views should contain only view-related logic:
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With