Проблемы с get_context_data в ListView (django)

Мне нужно показать в шаблоне две модели:

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

и создал ListView этого

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()

Мне нужно создать фильтр одного и того же "измерения", чтобы в шаблоне отображались только субразмерения этого измерения.

мой шаблон dimension.html:

{% include 'base.html'%}
{% block content %}
<div class="row">
    {% for dimension in dimensions %}
    <div class="col">
        <div class="card" style="width: 18rem;">
        <a class="">{{dimension.name}}</a>
        <div class="card-body"> 
        <ul>
        {% for subdimension in subdimensions %}
        <li>{{subdimension.name}}</li>
        {% endfor %}
        </ul>
        </div> 
        </div>
    </div> 
    {% endfor %}
</div>
{% endblock %}

но если вы заметили, покажите все субмерности во всех картах, а не только субмерности этих измерений.

Manager.py возвращает только объекты с фильтром active=True и order_by('sort_order')

Вы можете сделать это при неэффективном рендеринге, но если у вас 100-200 субразмеров - это не должно быть проблемой.

{% for dimension in dimensions %}
<div class="col">
    <div class="card" style="width: 18rem;">
    <a class="">{{dimension.name}}</a>
    <div class="card-body"> 
    <ul>
    {% for subdimension in subdimensions %}
    {% if subdimension.dimension == dimension %}
    <li>{{subdimension.name}}</li>
    {% endif %}
    {% endfor %}
    </ul>
    </div> 
    </div>
</div> 
{% endfor %}

Альтернативно, вы можете аннотировать все размеры с соответствующими субразмерами в представлении.

# 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

и затем в шаблоне

{% for dimension in dimensions %}
<div class="col">
    <div class="card" style="width: 18rem;">
    <a class="">{{dimension.name}}</a>
    <div class="card-body"> 
    <ul>
    {% for subdimension in dimension.all_dimensions %}
    <li>{{subdimension.name}}</li>
    {% endfor %}
    </ul>
    </div> 
    </div>
</div> 
{% endfor %}

(... или переключитесь на рендеринг шаблона Jinja2 для доступа к dimension.subdimension_set.all() непосредственно в шаблоне)

Также вы можете посмотреть на LoginRequiredMixin вместо method_decorator(login_required)

Вернуться на верх