如何基于Django模型生成带自增唯一主键的跟踪数据报告
解决方案
一、先修正现有模型的基础问题
你现有模型有几个语法和规范问题先调整,调整后可以直接得到你要的自增跟踪ID,同时天然支持分批次录入数据:
from django.db import models from django.core.validators import RegexValidator # 假设你已提前定义好CourseChoices模型和batch_pattern校验规则 batch_pattern = RegexValidator(r'^[0-9A-Z-]+$', '仅支持字母、数字和横杠') class Student(models.Model): # 修正参数拼写错误:primarykey改为primary_key roll_number = models.IntegerField(primary_key=True) name = models.CharField(max_length=50) email = models.EmailField(max_length=60) city = models.CharField(max_length=20) def __str__(self): return f"{self.roll_number}-{self.name}" class Course(models.Model): # 外键字段命名为student更符合语义,自动关联Student的roll_number主键 student = models.ForeignKey(Student, on_delete=models.CASCADE, related_name='courses') course = models.ForeignKey(CourseChoices, on_delete=models.CASCADE) class Fee(models.Model): # Django默认会给未显式指定主键的模型新增自增id字段,直接作为交易跟踪ID使用即可 student = models.ForeignKey(Student, on_delete=models.CASCADE, related_name='fee_records') amount_to_be_paid = models.DecimalField(max_digits=7, decimal_places=2, default=0) discount = models.DecimalField(max_digits=5, decimal_places=2, default=0) # 统一改为蛇形命名,符合Django编码规范 final_amount_to_be_paid = models.DecimalField(max_digits=7, decimal_places=2, default=0) amount_received = models.DecimalField(max_digits=7, decimal_places=2, default=0) balance = models.DecimalField(max_digits=7, decimal_places=2, default=0) batch = models.CharField(validators=[batch_pattern], max_length=20)
调整后三个模型完全独立,支持分批次录入:先录入学生基础信息,后续随时可以给已存在的学生补充录入选课、缴费数据,不需要一次性提交所有字段。
二、合并数据展示实现
方案1:Django Admin后台快速实现
如果你要在Django自带的后台展示合并报告,直接自定义Fee模型的Admin配置即可:
from django.contrib import admin from .models import Student, Course, Fee @admin.register(Fee) class FeeAdmin(admin.ModelAdmin): # list_display配置展示列,id就是你需要的自增唯一跟踪ID list_display = ('id', 'get_student_roll', 'get_student_name', 'get_student_email', 'get_courses', 'amount_to_be_paid', 'discount', 'final_amount_to_be_paid', 'amount_received', 'balance', 'batch') list_filter = ('batch', 'student__city') search_fields = ('student__roll_number', 'student__name', 'batch') # 自定义方法拉取学生基础信息 def get_student_roll(self, obj): return obj.student.roll_number get_student_roll.short_description = '学号' def get_student_name(self, obj): return obj.student.name get_student_name.short_description = '姓名' def get_student_email(self, obj): return obj.student.email get_student_email.short_description = '邮箱' # 自定义方法拉取学生所有选课信息 def get_courses(self, obj): return "、".join([c.course.name for c in obj.student.courses.all()]) get_courses.short_description = '所选课程'
配置完成后,Fee模型的后台列表页就会直接展示三张表合并的所有数据。
方案2:自定义视图/报告实现
如果要在前端页面或者导出报告里展示,用Django ORM关联查询即可,不需要额外新建模型:
# 视图层查询代码,一次性关联查询所有数据,避免N+1性能问题 from .models import Fee def fee_report(request): fee_records = Fee.objects.select_related('student').prefetch_related('student__courses').all() # 传到模板里循环渲染即可,每条记录的id就是唯一跟踪ID return render(request, 'fee_report.html', {'fee_records': fee_records})
模板层循环渲染示例:
<table border="1"> <tr> <th>跟踪ID</th> <th>学号</th> <th>姓名</th> <th>邮箱</th> <th>城市</th> <th>所选课程</th> <th>应缴金额</th> <th>折扣</th> <th>实际应缴</th> <th>已缴金额</th> <th>余额</th> <th>批次</th> </tr> {% for fee in fee_records %} <tr> <td>{{ fee.id }}</td> <td>{{ fee.student.roll_number }}</td> <td>{{ fee.student.name }}</td> <td>{{ fee.student.email }}</td> <td>{{ fee.student.city }}</td> <td>{% for course in fee.student.courses.all %}{{ course.course.name }}、{% endfor %}</td> <td>{{ fee.amount_to_be_paid }}</td> <td>{{ fee.discount }}</td> <td>{{ fee.final_amount_to_be_paid }}</td> <td>{{ fee.amount_received }}</td> <td>{{ fee.balance }}</td> <td>{{ fee.batch }}</td> </tr> {% endfor %} </table>
内容的提问来源于stack exchange,提问作者noob87
相关产品推荐
相关产品推荐

