Jonathan
Jonathan

Reputation: 539

Combining multiple django apps into one view, what am I doing wrong?

I have a Django project with multiple apps that I need to combine and render as a single page. I have the following sections of code:

One of the views I'm trying to aggregate with other views:

class ResourceList(generic.View):
    model = Submissions
    template_name = 'url_list.html'

    def get(self, request, *args, **kwargs):
        resources = Submissions.objects.all()
        return render_to_string(self.template_name, {'object_list': resources})

The view I'm trying to use to aggregate my apps:

class Index(View):

    def get(self, request, *args, **kwars):
        renderable = {
            'content': ResourceList(),
            'login': LoginView() # I don't care about the LoginView at the moment.
        }
        return render(request, 'index.html', renderable)

url_list.html

{% extends "base.html" %} <!--I've removed this, it did nothing -->
{% block content }
    {{ object.url}}
<ul>
    {% for resource in object_list %}
    <li> {{resource.url}} {{ resource.id }} {{ resource.rating }}</li>
    {% endfor %}
</ul>
{% endblock %}

index.html

<head>
    <title>HI</title>
</head>

<body>
    {% block login %} login {% endblock %} {% block content %} content {% endblock %}
</body>

</html>

The problem is that it just renders "login content" when I go to the test url I've got set up for the page. If I change render_to_string to render_to_response and go to the url I have set up to render just that view everything works perfectly. What's going on here?

Things I've tried:

Upvotes: 0

Views: 1722

Answers (1)

spectras
spectras

Reputation: 13552

You cannot do this like that. Views are glorified functions. They have a single entry point (dispatch()) that is invoked by Django internals, and invokes the correct method on itself, depending on the HTTP method (here, get()). Casting the view to a string will just display its name, not call it.

If you want to aggregate the behaviors of multiple view, you have several options.

  • you could extract those behaviors in functions, and have your actual views call those functions.
  • you could make mixins, and mix them into the views.

For instance:

from django.views.generic.base import ContextMixin

class ResourceListMixin(ContextMixin):
    def get_resource_list(self):
        # we put it in a separate method to allow easy overriding
        return Submissions.objects.all()

    def get_context_data(self, **kwargs):
        kwargs['resources'] = self.get_resource_list()
        return super(ResourceListMixin, self).get_context_data(**kwargs)

Now you can mix that into any view, and it will automagically know about{{ resources }}. For instance:

from django.views.generic.base import TemplateView

class IndexView(ResourceListMixin, TemplateView):
    template_name = 'index.html'
    # nothing else here, we leverage the power of Django's
    # TemplateView - it will do everything by itself

Then the IndexView view will render the index.html template, and it will be able to do {% for resource in resources %}.

Upvotes: 1

Related Questions