ListView (django) 中 get_context_data 的问题

problems with get_context_data in 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' 以便在模板中仅显示该维度的子维度。

我的模板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 仅 returns 具有过滤器 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)