1、表結構

class Student(models.Model): """ 學生表(已報名) """ customer = models.OneToOneField(verbose_name='客戶信息', to='Customer',on_delete=models.CASCADE,null=True,blank=True) class_list = models.ManyToManyField(verbose_name="已報班級", to='ClassList', blank=True,related_name="students") emergency_contract = models.CharField(max_length=32, blank=True, null=True, verbose_name='緊急聯系人') company = models.CharField(verbose_name='公司', max_length=128, blank=True, null=True) location = models.CharField(max_length=64, verbose_name='所在區域', blank=True, null=True) position = models.CharField(verbose_name='崗位', max_length=64, blank=True, null=True) salary = models.IntegerField(verbose_name='薪資', blank=True, null=True) welfare = models.CharField(verbose_name='福利', max_length=256, blank=True, null=True) date = models.DateField(verbose_name='入職時間', help_text='格式yyyy-mm-dd', blank=True, null=True) memo = models.CharField(verbose_name='備注', max_length=256, blank=True, null=True) def __str__(self): return self.customer.name class ClassStudyRecord(models.Model): """ 上課記錄表 (班級記錄) """ class_obj = models.ForeignKey(verbose_name="班級", to="ClassList",on_delete=models.CASCADE) day_num = models.IntegerField(verbose_name="節次", help_text=u"此處填寫第幾節課或第幾天課程...,必須為數字") teacher = models.ForeignKey(verbose_name="講師", to='UserInfo',on_delete=models.CASCADE) date = models.DateField(verbose_name="上課日期", auto_now_add=True) course_title = models.CharField(verbose_name='本節課程標題', max_length=64, blank=True, null=True) course_memo = models.TextField(verbose_name='本節課程內容概要', blank=True, null=True) has_homework = models.BooleanField(default=True, verbose_name="本節有作業",) homework_title = models.CharField(verbose_name='本節作業標題', max_length=64, blank=True, null=True) homework_memo = models.TextField(verbose_name='作業描述', max_length=500, blank=True, null=True) exam = models.TextField(verbose_name='踩分點', max_length=300, blank=True, null=True) def __str__(self): return "{0} day{1}".format(self.class_obj, self.day_num) class StudentStudyRecord(models.Model): ''' 學生學習記錄 ''' student = models.ForeignKey(verbose_name="學員", to='Student',on_delete=models.CASCADE) classstudyrecord = models.ForeignKey(verbose_name="第幾天課程", to="ClassStudyRecord",on_delete=models.CASCADE) record_choices = (('checked', "已簽到"), ('vacate', "請假"), ('late', "遲到"), ('noshow', "缺勤"), ('leave_early', "早退"), ) record = models.CharField("上課紀錄", choices=record_choices, default="checked", max_length=64) score_choices = ((100, 'A+'), (90, 'A'), (85, 'B+'), (80, 'B'), (70, 'B-'), (60, 'C+'), (50, 'C'), (40, 'C-'), (0, ' D'), (-1, 'N/A'), (-100, 'COPY'), (-1000, 'FAIL'), ) score = models.IntegerField("本節成績", choices=score_choices, default=-1) homework_note = models.CharField(verbose_name='作業評語', max_length=255, blank=True, null=True) note = models.CharField(verbose_name="備注", max_length=255, blank=True, null=True) homework = models.FileField(verbose_name='作業文件', blank=True, null=True, default=None) stu_memo = models.TextField(verbose_name='學員備注', blank=True, null=True) date = models.DateTimeField(verbose_name='提交作業日期', auto_now_add=True) def __str__(self): return "{0}-{1}".format(self.classstudyrecord, self.student) class Meta: unique_together=["student","classstudyrecord"] # 學生記錄表是由上課記錄表批量生成的
表結構分析: 1、學生學習記錄表和學生表是多對一的關系;一個學生有多條學習記錄 2、學生學習記錄和班級記錄是多對一的關系;一條班級記錄是這個班所有學生的學習記錄
2、實現功能
班級記錄:
學生學習詳細記錄:
批量創建: 1、獲取所有班級的班級記錄展示到前端頁面; 2、前端批量選擇班級記錄,提交到后端,前端提交時攜帶着每個班級記錄的pk值; 3、后端通過前端提交過來的pk值連表找到每個班級的所有學生; 4、批量將每個班級的上課記錄添加給這個班的每一個學生; 批量更新: 批量更新時需要注意,由於我們是批量修改的,所以前端在提交數據的時候必須標明我們修改的是哪個學生的學習記錄,一般我們用這個學生的id來標注,這樣后端在更新數據的時候就拿着這個學生的id去更新
自定義版本批量更新

# 批量將班級記錄更新給這個班級的每個學生 class Class_study_records(View): # 展示上課記錄表內容 def get(self, request): class_obj = models.ClassStudyRecord.objects.all() return render(request, "class_study_records.html", {"class_obj": class_obj}) # 批量將班級的上課記錄添加給班級的所有學生 def post(self, request): action = request.POST.get("action") selected_id = request.POST.getlist("selected_id") if hasattr(self, action): getattr(self, action)(selected_id) # 這樣返回頁面減少一次重定向 return self.get(request) # 批量創建學生學習記錄 def batch_record(self, selected_id): # 循環每一個班級的上課記錄 for record in selected_id: # 通過班級記錄找到班級的所有學生 all_student = models.ClassStudyRecord.objects.get(pk=record).class_obj.students.all() li = [] # 將班級記錄添加給班級的所有學生 for student in all_student: obj = models.StudentStudyRecord( student=student, classstudyrecord_id=record ) li.append(obj) models.StudentStudyRecord.objects.bulk_create(li) # 自定義版本 # 批量更新學生學習記錄 class Student_study_records(View): def get(self, request, record_id): # 通過前端發過來的班級記錄的id找到該班級 class_obj = models.ClassStudyRecord.objects.get(pk=record_id) # 找到這個課程記錄所生成的所有學生學習記錄 student_obj = models.StudentStudyRecord.objects.filter( classstudyrecord=class_obj) # 通過調用類中的屬性找到所有可以選擇的成績 score_choices = models.StudentStudyRecord.score_choices return render(request, "student_study_records1.html", {"student_obj": student_obj, "class_obj": class_obj, "score_choices": score_choices}) # 因為form表單是在當前頁提交,url會帶有一個id值, def post(self, request, record_id): student_dic = request.POST # print(student_dic) # <QueryDict: {'csrfmiddlewaretoken': ['igIDxQDr1xLFmyRGXpmtED6aE9AOtyQosGJq1WI5VNabN07O1aQuLzO6G9mWLNaK'], 'score_11': ['60'], 'homework_note_11': ['1'], 'score_12': ['0'], 'homework_note_12': ['2']}> """ { 1:{'score':85,'homework_note':'333'}, 2:{'score':85,'homework_note':'333'} } """ data_dict = {} for key, value in student_dic.items(): if key == "csrfmiddlewaretoken": continue field, pk = key.rsplit("_", 1) # 往字典中的同一個key里,插入多條value,防止第二次添加的把第一條數據替換掉 if pk in data_dict: data_dict[pk][field] = value else: data_dict[pk] = { field: value, } for spk, sdata in data_dict.items(): models.StudentStudyRecord.objects.filter(**{"pk": spk}).update(**sdata) return self.get(request, record_id)

{% extends "template.html" %} {% block countent %} <section class="content"> <div class="row"> <div class="col-xs-12"> <div class="box"> <form action="" method="post"> {% csrf_token %} <select name="action" id="" class="form-control" style="width: 200px;display: inline-block;margin-top: 10px;margin-left: 9px"> <option value="batch_record">批量更新學生學習記錄</option> </select> <input type="submit" value="go" class="btn btn-danger" style="vertical-align: 1px"> <!-- /.box-header --> <div class="box-body"> <table id="example2" class="table table-bordered table-hover"> <thead> <tr> <th> <input type="checkbox" id="choice"> </th> <th>序號</th> <th>班級</th> <th>節次</th> <th>講師</th> <th>課程標題</th> <th>學生學習詳細記錄</th> <th>操作</th> </tr> </thead> <tbody> {% for record in class_obj %} <tr> <td> <input type="checkbox" name="selected_id" value="{{ record.pk }}"> </td> <td>{{ forloop.counter }}</td> <td>{{ record.class_obj }}</td> <td>{{ record.day_num }}</td> <td>{{ record.teacher }}</td> <td>{{ record.course_title }}</td> <td><a href="{% url "student_study_records" record.pk %}">詳細記錄</a></td> <td> <a href="" class="btn btn-primary btn-sm">編輯</a> <a href="" class="btn btn-danger btn-sm">刪除</a> </td> </tr> {% endfor %} </tbody> </table> </div> </form> <!-- /.box-body --> </div> <!-- /.box --> <!-- /.box --> </div> <!-- /.col --> </div> <!-- /.row --> </section> {% endblock %} {% block js %} $("#choice").click(function () { // 獲取當前選中的狀態true或false var state = $(this).prop("checked"); $("[name=selected_id]").prop("checked",state) }) {% endblock %}

{% extends "template.html" %} {% block countent %} <h3>班級:{{ class_obj.class_obj }}第{{ class_obj.day_num }}天</h3> <div class="container-fluid"> <form action="" method="post"> {% csrf_token %} <input type="submit" value="提交"> <table class="table table-hover table-bordered "> <thead> <tr> <th>序號</th> <th>學員</th> <th>第幾天課程</th> <th>上課記錄</th> <th>本節成績</th> <th>批語</th> </tr> </thead> <tbody> {% for student in student_obj %} <tr> <td>{{ forloop.counter }}</td> <td>{{ student.student }}</td> <td>{{ student.classstudyrecord }}</td> <td> {{ student.get_record_display }} </td> <td> <select name="score_{{ student.pk }}" id=""> {% for choices in score_choices %} {% if student.score == choices.0 %} <option selected value="{{ choices.0 }}">{{ choices.1 }}</option> {% else %} <option value="{{ choices.0 }}">{{ choices.1 }}</option> {% endif %} {% endfor %} </select> </td> <td> <textarea name="homework_note_{{ student.pk }}" id="" cols="20" rows="1">{{ student.homework_note|default:'' }}</textarea> </td> </tr> {% endfor %} </tbody> </table> </form> </div> {% endblock %}
modelformset_factory

from django.forms.models import modelformset_factory from django import forms class StudyRecordDeialModelForm(forms.ModelForm): class Meta: model = models.StudentStudyRecord # 指定表 # fields = "__all__" # 指定驗證字段 fields = ["score","homework_note"] # modelformset_factory class Student_study_records(View): def get(self, request, record_id): # 通過前端發過來的班級記錄的id找到該班級 class_obj = models.ClassStudyRecord.objects.get(pk=record_id) # 獲取這個班級的所有學生學習記錄表 student_obj = models.StudentStudyRecord.objects.filter(classstudyrecord=class_obj) # 用StudentStudyRecord張表指定哪個modelform,對哪些數據進行加工 form_set_obj = modelformset_factory(model=models.StudentStudyRecord,form=StudyRecordDeialModelForm,extra=0) # 指定加工表里的哪些數據 formset = form_set_obj(queryset=student_obj) return render(request, "student_study_records1.html",{"formset":formset}) # form表單是在當前頁提交,url會帶有一個id值, def post(self, request, record_id): # 通過前端發過來的班級記錄的id找到該班級 class_obj = models.ClassStudyRecord.objects.get(pk=record_id) # 獲取這個班級的所有學生學習記錄表 student_obj = models.StudentStudyRecord.objects.filter(classstudyrecord=class_obj) # 用StudentStudyRecord張表指定哪個modelform,對哪些數據進行加工 form_set_obj = modelformset_factory(model=models.StudentStudyRecord, form=StudyRecordDeialModelForm, extra=0) # 將前端提交過來的數據交給這個對象去處理 formset = form_set_obj(request.POST) # modelform對數據進行驗證 if formset.is_valid(): # 驗證成功保存到數據庫 formset.save() else: # 打印錯誤信息 print(formset.errors) return self.get(request, record_id)

{% extends "template.html" %} {% block countent %} <h3>班級:{{ class_obj.class_obj }}第{{ class_obj.day_num }}天</h3> <div class="panel panel-default"> <div class="panel-heading">學習記錄</div> <div class="panel-body"> <div style="width: 680px;margin: 0 auto;"> <form method="post" action=""> {% csrf_token %} {{ formset.management_form }} <!-- 這句話一定要加上,固定的昂 --> <table class="table table-bordered"> <thead> <tr> <th>姓名</th> <th>考勤</th> <th>作業成績</th> <th>作業評語</th> </tr> </thead> <tbody> {% for form in formset %} <tr> {{ form.id }} <!--必須用id不能用pk,用來標識是修改的哪條數據--> <td>{{ form.instance.student }}</td> <!--默認樣式是下拉選擇框,指定instance顯示原數據的值--> {# <td>{{ form.instance.student }}</td>#} <td>{{ form.instance.get_record_display }} </td> {# <td>{{ form.instance.get_record_display }} </td>#} <td>{{ form.score }} </td> <td>{{ form.homework_note }}</td> </tr> {% endfor %} </tbody> </table> <input type="submit" value="保存"> </form> </div> </div> </div> {% endblock %}
注意前端頁面渲染時必須加上,固定寫法
{{ formset.management_form }}
我們在前端提交數據的時候必須用id來標識我們修改的是哪條數據,用於后端進行識別后保存進數據庫,
該字段在前端頁面是不顯示的;
注意:不能用pk做標識符,pk默認是從0開始的,不能用pk,不能用pk,不能用pk,重要的事情說三遍!!!😊😊😊
# 用StudentStudyRecord張表指定哪個modelform,對哪些數據進行加工 form_set_obj = modelformset_factory(model=models.StudentStudyRecord,form=StudyRecordDeialModelForm,extra=0) # 通過extra參數控制多顯示的標簽
django默認生成的都會做成下拉框的樣式
<!--默認樣式是下拉選擇框,指定instance顯示原數據的值--> <td>{{ form.instance.student }}</td>