Reputation: 3385
I want to have the following:
A template view (actually my landing page), that contains a number of items, including a list view.
Now, I have a list view that works when I map it to it's own url:
app/views.py
class MymodelListView(ListView):
model = Mymodel
context_object_name = "mymodel_list"
app/urls.py
app_name = "myapp"
urlpatterns = [
...
path("mlist/", MymodelListView.as_view(), name="mlist"),
...
]
app/../mymodel_list.html
{% extends 'base.html' %}
{% block content %}
<ul>
{% for adventure in adventure_list %}
<li>
<a href="{{ adventure.get_absolute_url }}">{{ adventure.title }}</a>
</li>
{% endfor %}
</ul>
{% endblock content %}
Now this works as expected, and displays all records from Mymodel at the "mlist" link.
However, I'd like to embed this into my index.html TemplateView. My thought was to use a snippet and have this in index.html
{% include 'myapp/_mymodel_list.html' with mymodel_list=mymodel_list %}
(Not sure if the "with" part is required, but it seems like I should need to pass the list from the main template to the snippet. Doesn't work either way anyway at the moment due to more basic issues).
So then I have my main homepage view setup as follows:
class HomePageView(TemplateView):
template_name = "index.html"
def get_context_data(self, *args, **kwargs):
context = super(HomePageView, self).get_context_data(*args, **kwargs)
context["adventure_list"] = MymodelListView.get_context_data()
print(context)
return context
But this crashes with:
Exception Type: TypeError at /
Exception Value: super(type, obj): obj must be an instance or subtype of type
Same if I pass self into MymodelListView.get_context_data(self)
.
Now as far as I can see, the Mymodel get context is confused because it's being passed a HomePage context and it's all a bit wrong.
Is what I'm trying to do just completely wrong? Is that why I can't find any helpful hints with my (usually reasonably reliable) google-fu? If so, what approach should I be taking instead?
I'd like to re-use the Mymodel list view in other pages (albeit possibly changing the filtering criteria), hence my attempt to do it like this, in a DRY fashion.
Upvotes: 0
Views: 505
Reputation: 1413
The problem you're seeing is that you're trying to call a method of MymodelListView
with an instance of HomePageView
. Since HomePageView
doesn't inherit from MymodelListView
Python can't do that and is throwing an error. You have a few ways that you can solve this.
myapp/views.py
# The first approach is to use Django's included mixin to get the
# queryset and include it in the context. This is a bit redundant and
# won't include any logic used in your ListView.
from django.views.generic.list import MultipleObjectMixin
class HomePageView(MultipleObjectMixin, TemplateView):
context_object_name = 'adventure_list'
model = Mymodel
template_name = 'index.html'
# Your second option is to manually include the queryset. Again, this
# won't include any login from the ListView.
class HomePageView(TemplateView):
template_name = 'index.html'
def get_context_data(self, **kwargs):
kwargs.setdefault('adventure_list', Mymodel.objects.all())
return super().get_context_data(**kwargs)
# This is the option that I would suggest. Inherit from the ListView
# that you've already written and give it its own template and context
# name. I'm pretty sure this should do exactly what you want.
class HomePageView(MymodelListView):
context_object_name = 'adventure_list'
template_name = 'index.html'
Another issue I foresee is that you're trying to include
an entire HTML file. I doubt that will work well for you. You're probably better off putting your list inside a file specifically to be included and then using that in both places. The only think you'll duplicate is the include
tag.
templates/index.html
...
<!-- If the context name doesn't change you don't need to assign it and
Django will render the included file correctly. -->
{% include 'myapp/include_list.html' %}
...
templates/myapp/mymodel_list.html
{% extends 'base.html' %}
{% block content %}
{% include 'myapp/include_list.html' with adventure_list=mymodel_list %}
{% endblock %}
templates/myapp/include_list.html
<ul>
{% for adventure in adventure_list %}
<li><a href="{{ adventure.get_absolute_url }}">{{ adventure.title }}</a></li>
{% endfor %}
</ul>
Upvotes: 2