【发布时间】:2023-03-20 05:55:01
【问题描述】:
我使用 Django 1.8.4 和 Python 3.4
我有一个锦标赛模型,它定义了一个在订阅被禁止时返回字符串的方法。
class Tournament(models.Model):
name = models.CharField(max_length=200, null=True, blank=True)
subscriptions = models.ManyToManyField('ap_users.Profile')
is_subscription_open = models.BooleanField(default=True)
# ...
def why_subscription_impossible(self, request):
if not request.user.profile.is_profile_complete():
return 'Your profile is not complete'
elif not self.is_subscription_open:
return 'Subscriptions are closed'
elif <another_condition>:
return 'Another error message'
return None
我想显示锦标赛列表,使用一个通用的 ListView,我想使用方法的结果来修改它的显示方式:
<table class="table">
<thead>
<td>Tournament</td>
<td>Subscription</td>
</thead>
{% for tournament in tournament_list %}
<tr>
<td>{{ tournament.name }}</td>
<td>
{% if tournament.why_subscription_impossible %}
{{ tournament.why_subscription_impossible }}
{% else %}
<a href="{% url 'ap_tournament:subscribe' tournament.id %}">Subscribe</a>
{% endif %}
</td>
</tr>
{% endfor %}
</table>
视图是一个基于类的通用视图,继承自generic.ListView。
class IndexView(generic.ListView):
template_name = 'ap_tournament/index.html'
def get_queryset(self):
return Tournament.objects.all()
显示的解决方案不起作用,因为我需要传递当前请求,以获取有关登录用户的信息。所以我尝试将方法的结果添加到视图中的上下文中
class IndexView(generic.ListView):
template_name = 'ap_tournament/index.html'
def get_queryset(self):
return Tournament.objects.all()
def get_context_data(self, **kwargs):
context = super(IndexView, self).get_context_data(**kwargs)
additional_ctx_info = []
for tournament in self.get_queryset():
additional_ctx_info.append({
'reason_to_not_subscribe': tournament.why_subscription_impossible(self.request)
})
context['subscr_info'] = additional_ctx_info
return context
显然,这也行不通。我不知道如何使用锦标赛列表中的当前索引访问subscr_info[n]。我知道forloop.counter0 来获取索引,但我不能在模板中使用它(或者我不知道如何)。我试过了:
{{ subscr_info.forloop.counter0.reason_to_not_subscribe }}{{ subscr_info.{{forloop.counter0}}.reason_to_not_subscribe }}
我还尝试在 get_queryset() 视图方法中注释 QuerySet 并阅读了有关 aggregate() 的信息,但我觉得这只适用于数据库支持的操作(AVG、COUNT、MAX 等)。
我也觉得在我的情况下使用过滤器或模板标签不起作用,因为我需要在if标签中使用方法的结果。
是否有更好的解决方案或完全不同的方法来实现我想要的?
【问题讨论】:
-
我认为
why_subscription_impossible方法应该放在其他地方,但不在模型中。模型方法应该对对象的属性做一些事情(并且应该特定于该对象/行,否则对于多行将其放在模型管理器中) -
here 表示从 django 1.8 开始,现在可以在
annotate中使用任何类型的表达式。因此,为避免进行多个查询(在 get_context_data 中获取查询集),请将您的方法移到任何类之外(例如到您的 view.py)并在 get_queryset 中执行return Tournament.objects.annotate(reason=why_subscription_impossible(self.request))。试试看它是否有效,这将是最干净的解决方案。 -
这个问题的例子被简化了,但是这个方法实际上执行了很多检查,包括锦标赛的字段。出于这个原因,我可以将它移动到其他地方(并向函数添加锦标赛参数),但我不能使用这个新函数作为注释(因为我不能在每次调用时传递不同的锦标赛对象)。我更新了代码 sn-ps。
标签: python django django-queryset