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

如何在Django中按指定结构展示模型数据并完成薪资核算?

Hey there! Let's walk through how to build these two data views in Django—one grouped by date and worker, and another worker-centric view with all those calculated salary fields. I'll break it down step by step so it's easy to follow.


1. First: Align Your Models (Example Setup)

Since you mentioned your model structure matches a diagram, let's start with a realistic example you can tweak to fit your actual data:

from django.db import models

class Worker(models.Model):
    name = models.CharField(max_length=100)
    designation = models.CharField(max_length=50)
    basic_monthly_salary = models.DecimalField(max_digits=10, decimal_places=2)
    epf_contribution_rate = models.DecimalField(max_digits=4, decimal_places=2, default=12.0)  # % of salary
    esic_contribution_rate = models.DecimalField(max_digits=4, decimal_places=2, default=4.75)  # % of salary

class DailyWorkRecord(models.Model):
    worker = models.ForeignKey(Worker, on_delete=models.CASCADE, related_name='daily_records')
    work_date = models.DateField()
    regular_hours = models.DecimalField(max_digits=5, decimal_places=2)
    overtime_hours = models.DecimalField(max_digits=5, decimal_places=2, default=0)
    other_deductions = models.DecimalField(max_digits=10, decimal_places=2, default=0)

2. View 1: Display Data by Date + Worker

We'll group records by date first, then list all worker entries under each date. Logic stays in the view—templates are for display only!

Step 2.1: Build the View

from django.shortcuts import render
from itertools import groupby
from .models import DailyWorkRecord

def date_worker_view(request):
    # Fetch records sorted by date (critical for groupby to work)
    all_records = DailyWorkRecord.objects.select_related('worker').order_by('work_date')
    # Group records by their work date
    grouped_records = groupby(all_records, key=lambda record: record.work_date)
    # Convert to a list of (date, record_list) pairs for easy template iteration
    date_groups = [(date, list(records)) for date, records in grouped_records]
    return render(request, 'date_worker_display.html', {'date_groups': date_groups})

Step 2.2: Template (date_worker_display.html)

<h1>按日期及劳工维度展示数据</h1>
{% for date, records in date_groups %}
    <h2>{{ date|date:"Y年m月d日" }}</h2>
    <table border="1" cellpadding="8">
        <thead>
            <tr>
                <th>劳工姓名</th>
                <th>岗位</th>
                <th>正常工时</th>
                <th>加班工时</th>
            </tr>
        </thead>
        <tbody>
            {% for record in records %}
                <tr>
                    <td>{{ record.worker.name }}</td>
                    <td>{{ record.worker.designation }}</td>
                    <td>{{ record.regular_hours }}</td>
                    <td>{{ record.overtime_hours }}</td>
                </tr>
            {% empty %}
                <tr><td colspan="4">当日无工作记录</td></tr>
            {% endfor %}
        </tbody>
    </table>
    <br>
{% endfor %}

3. View 2: Worker-Centric Display with Calculated Fields

For this view, we need to compute Per Day Salary, Total Salary, Net Salary, EPF, and ESIC for each worker. We'll handle calculations in the Worker model (reusable logic!) or the view, then pass the computed data to the template.

Step 3.1: Add Calculation Methods to the Worker Model

Add property methods and a monthly calculation method to keep logic encapsulated:

class Worker(models.Model):
    # ... existing fields ...

    @property
    def per_day_salary(self):
        # Assume 26 working days per month (adjust to your company's policy)
        return self.basic_monthly_salary / 26

    def get_monthly_pay_details(self, target_month, target_year):
        # Fetch all daily records for the worker in the target month/year
        monthly_records = self.daily_records.filter(
            work_date__month=target_month,
            work_date__year=target_year
        )
        
        # Aggregate basic data
        total_working_days = monthly_records.count()
        total_overtime = sum(record.overtime_hours for record in monthly_records)
        total_other_deductions = sum(record.other_deductions for record in monthly_records)
        
        # Calculate core salary components
        hourly_rate = self.per_day_salary / 8  # Assume 8-hour workday
        regular_pay = self.per_day_salary * total_working_days
        overtime_pay = total_overtime * hourly_rate * 1.5  # 1.5x overtime rate
        total_salary = regular_pay + overtime_pay
        
        # Calculate statutory deductions
        epf_deduction = total_salary * (self.epf_contribution_rate / 100)
        # ESIC applies only if total salary is ≤ ₹21,000/month (adjust based on your region)
        esic_deduction = total_salary * (self.esic_contribution_rate / 100) if total_salary <= 21000 else 0
        
        # Net salary = Total Salary - All Deductions
        net_salary = total_salary - (total_other_deductions + epf_deduction + esic_deduction)
        
        return {
            'per_day_salary': self.per_day_salary,
            'total_working_days': total_working_days,
            'total_overtime': total_overtime,
            'total_salary': total_salary,
            'epf_deduction': epf_deduction,
            'esic_deduction': esic_deduction,
            'net_salary': net_salary
        }

Step 3.2: Build the Worker-Centric View

from django.shortcuts import render
from datetime import datetime
from .models import Worker

def worker_centric_view(request):
    # Use current month/year by default (add GET params to let users select a month)
    current_month = datetime.now().month
    current_year = datetime.now().year
    
    all_workers = Worker.objects.all()
    worker_pay_data = []
    
    # Fetch pay details for each worker
    for worker in all_workers:
        pay_details = worker.get_monthly_pay_details(current_month, current_year)
        worker_pay_data.append({
            'worker': worker,
            **pay_details
        })
    
    return render(request, 'worker_centric_display.html', {'worker_pay_data': worker_pay_data})

Step 3.3: Template (worker_centric_display.html)

<h1>按劳工维度展示数据(含薪资计算)</h1>
<table border="1" cellpadding="8">
    <thead>
        <tr>
            <th>劳工姓名</th>
            <th>日薪</th>
            <th>工作天数</th>
            <th>总加班时长</th>
            <th>总薪资</th>
            <th>EPF扣除</th>
            <th>ESIC扣除</th>
            <th>净薪资</th>
        </tr>
    </thead>
    <tbody>
        {% for data in worker_pay_data %}
            <tr>
                <td>{{ data.worker.name }}</td>
                <td>₹{{ data.per_day_salary|floatformat:2 }}</td>
                <td>{{ data.total_working_days }}</td>
                <td>{{ data.total_overtime|floatformat:2 }}</td>
                <td>₹{{ data.total_salary|floatformat:2 }}</td>
                <td>₹{{ data.epf_deduction|floatformat:2 }}</td>
                <td>₹{{ data.esic_deduction|floatformat:2 }}</td>
                <td>₹{{ data.net_salary|floatformat:2 }}</td>
            </tr>
        {% empty %}
            <tr><td colspan="8">暂无劳工数据</td></tr>
        {% endfor %}
    </tbody>
</table>

Quick Tips for Improvement
  • Add a date picker in the worker-centric view to let users select different months/years (use GET parameters to pass month and year to the view).
  • Use Django's localize template tag to format currency/numbers according to your region.
  • For large datasets, use Django's database-level aggregation (annotate/aggregate) instead of Python loops to boost performance.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 18:57:33