I need to show in a template two models:
models.py:
class Dimension(TimeStampedModel):
level = models.ForeignKey('Level', verbose_name=_('Level'), on_delete=models.CASCADE)
name = models.CharField(verbose_name=('Name'), max_length=200)
active = models.BooleanField(verbose_name=_('Active'), default=True)
sort_order = models.PositiveIntegerField(verbose_name=_('sort order'), default=0)
class Meta:
verbose_name = _('Dimension')
verbose_name_plural = _('Dimensions')
def __str__(self):
return self.name
class Subdimension(TimeStampedModel):
dimension = models.ForeignKey('Dimension', verbose_name=_('Dimension'), on_delete=models.CASCADE)
name = models.CharField(verbose_name=('Name'), max_length=200)
active = models.BooleanField(verbose_name=_('Active'), default=True)
sort_order = models.PositiveIntegerField(verbose_name=_('sort order'), default=0)
objects = managers.SubdimensionManager()
class Meta:
verbose_name = _('Subdimension')
verbose_name_plural = _('Subdimensions')
def __str__(self):
return self.name
and created a ListView of this
views.py
class DimensionListView(generic.ListView):
model = models.Dimension
template_name = 'dimension.html'
context_object_name = 'dimensions'
@method_decorator(login_required)
def dispatch(self, request, *args, **kwargs):
self.user = self.request.user
self.level = self.get_level(pk=kwargs.get('level_pk'))
return super(DimensionListView, self).dispatch(request, *args, **kwargs)
def get_level(self, pk):
level = get_object_or_404(models.Level, pk=pk)
return level
def get_queryset(self):
queryset = super(DimensionListView, self).get_queryset()
return queryset.filter(active = True, level = self.level)
def get_context_data(self, **kwargs):
context = super(DimensionListView, self).get_context_data(**kwargs)
context['subdimensions'] = models.Subdimension.objects.filter(active=True, dimension__level=self.level )
return context
dimension_list_view = DimensionListView.as_view()
I need to created a filter of the same 'dimension' so that in the template show only the subdimensions of that dimension.
my template dimension.html:
{% include 'base.html'%}
{% block content %}
<div >
{% for dimension in dimensions %}
<div >
<div style="width: 18rem;">
<a >{{dimension.name}}</a>
<div >
<ul>
{% for subdimension in subdimensions %}
<li>{{subdimension.name}}</li>
{% endfor %}
</ul>
</div>
</div>
</div>
{% endfor %}
</div>
{% endblock %}
but if u notice, show all the subdimensiones in all cards, not only the subdimension of these dimension.
Manager.py only returns a objects with filter active=True and order_by('sort_order')
CodePudding user response:
You can do it with inefficient rendering, but if you have 100-200 subdimensions - it should not be a problem.
{% for dimension in dimensions %}
<div >
<div style="width: 18rem;">
<a >{{dimension.name}}</a>
<div >
<ul>
{% for subdimension in subdimensions %}
{% if subdimension.dimension == dimension %}
<li>{{subdimension.name}}</li>
{% endif %}
{% endfor %}
</ul>
</div>
</div>
</div>
{% endfor %}
Alternatively, you can annotate all dimensions with corresponding subdimensions in the view.
# views.py
class DimensionListView(generic.ListView):
...
def get_queryset(self):
queryset = super(DimensionListView, self).get_queryset()
# Save db hits with `prefetch_related`
return queryset.filter(active = True, level = self.level).prefetch_related('subdimension_set')
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
dims = list(context['dimensions'])
for d in dims:
d.all_subdimensions = list(d.subdimension_set.all())
context['dimensions'] = dims
return context
and then in template
{% for dimension in dimensions %}
<div >
<div style="width: 18rem;">
<a >{{dimension.name}}</a>
<div >
<ul>
{% for subdimension in dimension.all_dimensions %}
<li>{{subdimension.name}}</li>
{% endfor %}
</ul>
</div>
</div>
</div>
{% endfor %}
(... or switch to Jinja2
template rendering to access dimension.subdimension_set.all()
directly in template)
Also you can have a look at LoginRequiredMixin
instead of method_decorator(login_required)