You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django中如何根据关联模型状态在列表展示对应操作链接

问题描述

我做了一个带搜索框的用户列表,列表项里包含审批申请的超链接。需求是:对已批准申请的用户显示“已批准”按钮,未批准的显示“批准”链接。我尝试在循环里加条件判断,但现在未批准用户的“批准”按钮会重复显示多次,已批准用户则同时显示“批准”和“已批准”按钮。我是Django新手,卡在这里了,求解决办法。

现有代码

Models代码

class Fee(models.Model):
    applicant = models.OneToOneField(User, on_delete=models.CASCADE, null=True)
    email = models.CharField(max_length=30, null=True)
    phone = models.CharField(max_length=20, null=True)
    date = models.DateTimeField(auto_now_add=True)

def __str__(self):
    return f'Payments: {self.applicant}'

class Profile(models.Model):
    applicant = models.OneToOneField(User, on_delete=models.CASCADE, null = True)
    surname = models.CharField(max_length=20, null=True)
    othernames = models.CharField(max_length=40, null=True)
    gender = models.CharField(max_length=6, choices=GENDER, blank=True, null=True)

    def __str__(self):
        return f'{self.applicant.username}-Profile'

Views代码

def search_applicants(request):
    # 初始化空上下文
    context = {}
    # 搜索表单
    searchForm = SearchApplicantForm(request.GET or None)
    payments = Fee.objects.all()

    if searchForm.is_valid():
        # 获取搜索值
        value = searchForm.cleaned_data['value']
        # 用Q对象按姓氏或其他名称过滤
        user_filter = Q(surname__icontains = value) | Q(othernames__icontains = value)
        # 应用过滤条件到Profile对象
        list_submited = Profile.objects.filter(user_filter) 

    else:
        list_submited = Profile.objects.all()

    paginator = Paginator(list_submited, 5)
    page = request.GET.get('page')
    paged_list_submited = paginator.get_page(page)
    # 更新上下文变量
    context.update({
        'list_applicants':paged_list_submited,
        'searchForm':searchForm,
        'payments':payments,
    })

    return render(request, 'user/list_applicants.html', context)

HTML模板代码

<table class="table bg-white">
    <thead class="bg-info text-white">
        <tr>
            <th scope="col">#</th>
            <th scope="col">姓氏</th>
            <th scope="col">其他名称</th>
            <th scope="col">邮箱</th>
            <th scope="col">手机号</th>
            <th scope="col">操作</th>
        </tr> 
    </thead>
                    
    {% if list_applicants %}
    <tbody>
        {% for applicant in list_applicants %}
        <tr>
            <td>{{ forloop.counter }}</td>
            <td>{{ applicant.surname }}</td>
            <td>{{ applicant.othernames }}</td>
            <td>{{ applicant.applicant.email }}</td>
            <td>{{ applicant.applicant.profile.phone }}</td>
            <th>
                {% for fee in payments %}
                    {% if fee.applicant == applicant.applicant %}
                        <a class="btn btn-info btn-sm">已批准</a>
                    {% else %}
                        <a class="btn btn-info btn-sm" href="{% url 'approve-applicant' applicant.id %}">批准</a>
                    {% endif %}
                {% endfor %}
            </th>
        </tr>
        {% endfor %}
    </tbody>
    {% else %}                 
        暂无记录
    {% endif %}
</table>
问题原因

你当前的模板循环了所有payments记录,每一条Fee都会生成一个按钮:

  • 已批准用户:循环到他对应的Fee时显示“已批准”,但循环到其他Fee时,因不匹配会显示“批准”,导致同时出现两个按钮。
  • 未批准用户:每一条Fee都会触发else分支,生成一个“批准”按钮,按钮数量等于Fee表的总记录数。
解决方案

核心修复:去掉冗余循环,直接判断用户审批状态

因为Fee和User是OneToOne关系,可通过反向关联直接判断当前用户是否存在审批记录,无需循环所有payments:

修改HTML模板中操作列的代码:

<th>
    {% if applicant.applicant.fee %}
        <a class="btn btn-info btn-sm">已批准</a>
    {% else %}
        <a class="btn btn-info btn-sm" href="{% url 'approve-applicant' applicant.id %}">批准</a>
    {% endif %}
</th>

同时可以删除视图中payments = Fee.objects.all()和上下文里的'payments':payments,因为不再需要这个变量。

可选优化:提升查询性能

如果用户数量较多,为避免模板中出现N+1查询问题,可在视图中提前预取关联数据:

if searchForm.is_valid():
    value = searchForm.cleaned_data['value']
    user_filter = Q(surname__icontains = value) | Q(othernames__icontains = value)
    # 预取关联的User及对应的Fee
    list_submited = Profile.objects.filter(user_filter).select_related('applicant__fee')
else:
    list_submited = Profile.objects.all().select_related('applicant__fee')

额外优化:简化模板字段调用

模板里{{ applicant.applicant.profile.surname }}可直接写成{{ applicant.surname }},因为applicant本身就是Profile对象,无需绕路调用。

内容的提问来源于stack exchange,提问作者apollos

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 16:54:51