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

Django 1.11 ListView实现仅显示经前一部门审批的请求

Hey Gustavo, let's work through this approval flow challenge for your Django 1.11 municipal app. The goal is to make sure requests only show up in a department's list once all prior departments in the chain have signed off, right? Here's a step-by-step solution tailored to your model setup.

Step 1: Validate & Refine Your Model Structure

First, let's make sure your models have the necessary fields to track the approval sequence and status. Based on what you mentioned, here's a polished version you can align with:

# models.py
from django.db import models
from django.contrib.auth.models import User

class Secretaria(models.Model):
    name = models.CharField(max_length=100)
    # Add any other department-specific fields here

class Solicitacao(models.Model):
    title = models.CharField(max_length=200)
    description = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)
    # Store approval order as a comma-separated string of Secretaria IDs (e.g., "2,5,7")
    # This defines the order departments must approve the request
    approval_sequence = models.CharField(max_length=200, help_text="Comma-separated Secretaria IDs in approval order")

class SecretarioAprovacao(models.Model):
    request = models.ForeignKey(Solicitacao, on_delete=models.CASCADE, related_name='approvals')
    secretary = models.ForeignKey(Secretaria, on_delete=models.CASCADE)
    STATUS_CHOICES = (
        ('pending', 'Pending'),
        ('approved', 'Approved'),
        ('rejected', 'Rejected'),
    )
    status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='pending')
    approved_at = models.DateTimeField(null=True, blank=True)
    comments = models.TextField(blank=True)

    class Meta:
        # Ensure one approval record per department per request
        unique_together = ('request', 'secretary')

Pro tip: When a new Solicitacao is created, use a signal to auto-generate SecretarioAprovacao records for each department in approval_sequence (status set to pending). This avoids manual setup later.

Step 2: Filter Requests in Your View's get_context_data

Now, in your ListView, we'll filter the requests to only show those where all prior departments have approved, and the current department's approval is still pending (or not yet started).

Assuming your logged-in user is linked to a Secretaria via a OneToOneField (e.g., User.secretary), here's how to implement the logic:

# views.py
from django.db.models import Q, RawSQL
from django.views.generic import ListView
from .models import Solicitacao, SecretarioAprovacao

class DepartmentRequestListView(ListView):
    model = Solicitacao
    template_name = 'requests/department_requests.html'
    context_object_name = 'solicitacoes'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        current_secretary = self.request.user.secretary  # Get the logged-in user's department

        # 1. Start with requests that include the current department in their approval sequence
        # Use commas to avoid partial matches (e.g., ID 1 vs 11)
        queryset = Solicitacao.objects.filter(
            approval_sequence__icontains=f',{current_secretary.id},'
        )

        # 2. Filter out requests where any prior department hasn't approved yet
        # This uses PostgreSQL functions—adjust for MySQL if needed
        queryset = queryset.annotate(
            # Extract all department IDs that come before the current one in the sequence
            prior_depts=RawSQL(
                "SELECT array_to_string(array_remove(string_to_array(approval_sequence, ','), %s), ',')",
                [str(current_secretary.id)]
            )
        )

        # Ensure all prior departments have approved the request
        filtered_queryset = queryset.filter(
            ~Q(
                approvals__secretary_id__in=RawSQL("SELECT unnest(string_to_array(prior_depts, ','))::int", []),
                approvals__status__in=['pending', 'rejected']
            )
        )

        # 3. Only include requests where the current department's approval is pending or not started
        filtered_queryset = filtered_queryset.filter(
            Q(approvals__secretary=current_secretary, approvals__status='pending') |
            Q(approvals__secretary=current_secretary, approvals__isnull=True)
        )

        # Remove duplicate requests caused by joining with approval records
        filtered_queryset = filtered_queryset.distinct()

        context['solicitacoes'] = filtered_queryset
        return context
Step 3: Template Display

In your template, you can loop through the filtered requests and show relevant details, including the current approval status (if any):

<!-- templates/requests/department_requests.html -->
<h2>Pending Requests for {{ user.secretary.name }}</h2>

{% if solicitacoes %}
    <ul class="request-list">
        {% for req in solicitacoes %}
            <li class="request-item">
                <h3>{{ req.title }}</h3>
                <p>{{ req.description|truncatechars:200 }}</p>
                <small>Created: {{ req.created_at|date:"M d, Y" }}</small>

                {% with current_approval=req.approvals.filter(secretary=user.secretary).first %}
                    {% if current_approval %}
                        <p>Current Status: <strong>{{ current_approval.get_status_display }}</strong></p>
                        {% if current_approval.comments %}
                            <p>Previous Comments: {{ current_approval.comments }}</p>
                        {% endif %}
                    {% endif %}
                {% endwith %}

                <a href="{% url 'request_approval' req.id %}" class="btn">Review & Approve/Reject</a>
            </li>
        {% endfor %}
    </ul>
{% else %}
    <p>No pending requests for your department at this time.</p>
{% endif %}
Key Notes & Optimizations
  • Database Compatibility: The RawSQL above uses PostgreSQL functions (string_to_array, unnest). If you're on MySQL, replace these with equivalent functions like SUBSTRING_INDEX to split the approval sequence.
  • Indexing: Add database indexes to SecretarioAprovacao.request, SecretarioAprovacao.secretary, and Solicitacao.approval_sequence to speed up filtering.
  • Rejection Handling: The query above excludes requests where any prior department rejected it—adjust the ~Q clause if you want to handle rejected requests differently (e.g., notify the requester instead of hiding from departments).
  • Signal for Auto-Approvals: Add a post-save signal to Solicitacao that creates SecretarioAprovacao records for each department in approval_sequence when a request is created. This ensures every department has a pending approval entry from the start.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 10:11:21