一.批量生成数据
需求:点击【批量生成学习记录】后将下面的课程记录生成学习记录
表结构:
from django.db import models
from multiselectfield import MultiSelectField
from django.utils.safestring import mark_safe
class Customer(models.Model):
'''
客户表
'''
qq = models.CharField(verbose_name='QQ', max_length=64, help_text='qq号必须唯一')
qq_name = models.CharField(verbose_name='QQ昵称', max_length=64, null=True, blank=True)
name = models.CharField(verbose_name='姓名', max_length=32, blank=True, null=True, help_text='学员报名后,请改为真实姓名')
sex_type = (('male', '男'), ('female', '女'))
sex = models.CharField(verbose_name='性别', choices=sex_type, max_length=16, default='male', blank=True, null=True)
birthday = models.DateField(verbose_name='出生日期', default=None, help_text='格式yyyy-mm-dd', blank=True, null=True)
phone = models.CharField(verbose_name='手机号', max_length=16, blank=True, null=True)
source = models.CharField(verbose_name='客户来源', max_length=64, choices=source_type, default='qq')
introduce_from = models.ForeignKey('self', verbose_name='转介绍学员', blank=True, null=True, on_delete=models.CASCADE)
course = MultiSelectField(verbose_name='咨询课程', choices=course_choices) # 多选框
class_type = models.CharField(verbose_name='班级类型', max_length=64, choices=class_type_choices, default='fulltiem')
customer_note = models.CharField(verbose_name='客户备注', blank=True, null=True, max_length=64)
status = models.CharField(verbose_name='状态', choices=enroll_status_choices, max_length=64, default='unregistered',
help_text='选择客户此时的状态')
date = models.DateTimeField(verbose_name='咨询日期', auto_now_add=True)
next_date = models.DateField(verbose_name='预计再次跟进时间', blank=True, null=True)
# 用户表中存放的是自己公司的所有员工
consultant = models.ForeignKey('UserInfo', verbose_name='销售', related_name='customers', blank=True, null=True,
on_delete=models.CASCADE)
# 一个客户可以报多个班
class_list = models.ManyToManyField('ClassList', verbose_name='已报班级', blank=True)
class Meta:
ordering = ['id']
verbose_name = '客户信息表'
verbose_name_plural = '客户信息表'
def __str__(self):
return self.name + ":" + self.qq
def status_show(self):
status_color = {
'signed':'yellow',
'unregistered':'red',
'studying':'blue',
'paid_in_full':'green',
}
return mark_safe(f'''<span style="background-color: {status_color[self.status]}">{self.get_status_display()}</span>''')
class CourseRecord(models.Model):
"""课程记录表"""
day_num = models.IntegerField("节次", help_text="此处填写第几节课或第几天课程...,必须为数字")
date = models.DateField(auto_now_add=True, verbose_name="上课日期")
course_title = models.CharField('本节课程标题', max_length=64, blank=True, null=True)
course_memo = models.TextField('本节课程内容', max_length=300, blank=True, null=True)
has_homework = models.BooleanField(default=True, verbose_name="本节有作业")
homework_title = models.CharField('本节作业标题', max_length=64, blank=True, null=True)
homework_memo = models.TextField('作业描述', max_length=500, blank=True, null=True)
scoring_point = models.TextField('得分点', max_length=300, blank=True, null=True)
re_class = models.ForeignKey('ClassList', verbose_name="班级")
teacher = models.ForeignKey('UserInfo', verbose_name="讲师")
class Meta:
unique_together = ('re_class', 'day_num')
verbose_name = '课程记录表'
verbose_name_plural = '课程记录表'
def __str__(self):
return self.course_title
class StudyRecord(models.Model):
"""
学习记录表
"""
attendance = models.CharField("考勤", choices=attendance_choices, default="checked", max_length=64)
score = models.IntegerField("本节成绩", choices=score_choices, default=-1)
homework_note = models.CharField(max_length=255, verbose_name='作业批语', blank=True, null=True)
date = models.DateTimeField(auto_now_add=True)
note = models.CharField("备注", max_length=255, blank=True, null=True)
homework = models.FileField(verbose_name='作业文件', blank=True, null=True, default=None)
course_record = models.ForeignKey('CourseRecord', verbose_name="某节课程")
student = models.ForeignKey('Customer', verbose_name="学员")
class Meta:
unique_together = ('course_record', 'student')
verbose_name = '学习记录表'
verbose_name_plural = '学习记录表'
def __str__(self):
return self.attendance
技术分析:
批量生成学习记录,第一点要知道有多少学员在这个班级中,并且状态已经是学习中的,
怎么找到学员呢,CourseRecord表中有一个字段是re_class关联到班级表,ClassList表和客Customer
表是多对多的关系,这样可以通过CourseRecord中的re_class去查所在班级,通过班级表反向去查那些
客户在这些班级中:CourseRecord.re_class__customer_set.filter(status='studying')
结构图:
代码:
# 批量生成学习记录
def post(self,request):
action = request.POST.get('action')
cids = request.POST.getlist('cids')
if hasattr(self,action):
ret = getattr(self,action)(request,cids)
if ret:
return ret
return redirect('app04:course_record')
# 批量生成学习记录
def bulk_create_student(self,request,cids):
for cid in cids: #找到所有的课程记录
course_record = app04.models.CourseRecord.objects.filter(id=cid).first() # 查所有的课程记录
students = course_record.re_class.customer_set.filter(status='studying') # 通过课程记录找到所有的本节课程的所有学生的学习记录
obj_list = []
for student in students: #学员信息
obj = app04.models.StudyRecord( # 创建信息
course_record_id=cid, # 课程
student = student, # 学员
)
obj_list.append(obj)
try: # 如果已经生成过学习记录就给一个提示
app04.models.StudyRecord.objects.bulk_create(obj_list)
except IntegrityError:
return render(request,'crm/coursereord.html',{'uid_error':'学习记录已经存在!!!'})
二.modelformset
django admin后台之前展示的都是单个字段,如果想展示多个字段呢,需要自己拓展一下,以用户表示例,以前展示的字段内容:
修改后:
class UserInfoModel(admin.ModelAdmin):
list_display = ['username','password','email','telephone','is_active']
# Register your models here.
admin.site.register(models.UserInfo,UserInfoModel)
如果想实现多条记录同时编辑提交,可以新加一个属性:
class UserInfoModel(admin.ModelAdmin):
list_display = ['username','password','email','telephone','is_active']
list_editable = ['password','email','telephone','is_active'] # 编辑
效果:
项目中如何实现这种批量修改编辑呢,就需要用modelformset,这次实现的是点击学习记录,就跳转到学习记录页面并展示这门课程的所在班级的所有学员:
视图函数:
# 学习记录
class StudyRecordView(View):
def get(self,request,cid):
study_record = app04.models.StudyRecord.objects.filter(course_record_id=cid)
# 会把传递进来的modelform生成modelformset他自己的页面效果
formset_obj = modelformset_factory(app04.models.StudyRecord,StudyRecordModel, extra=0)
study_record_formset = formset_obj(queryset=study_record) #只创建那些数据
return render(request, 'crm/studentrecord.html', {'study_record_formset': study_record_formset})
def post(self,request,cid):
formset_obj = modelformset_factory(app04.models.StudyRecord, StudyRecordModel, extra=0)
study_record_formset = formset_obj(request.POST)
if study_record_formset.is_valid():
study_record_formset.save()
return redirect(request.path)
else:
return render(request, 'crm/studentrecord.html', {'study_record_formset': study_record_formset})
前端代码:
{% extends 'crm/starter.html' %}
{% load mytag %}
{% block title %}
<h1>学习记录展示</h1>
{% endblock %}
{% block contnet %}
<div class="form-inline">
<form action="" class="pull-right">
<div class="form-group pull-right">
<div class="form-group">
<select name="search_field" id="search_field" class="form-control">
<option value="student__name__contains">学员</option>
</select>
</div>
<input type="text" class="form-control" name="kw">
<button type="submit" class="btn btn-default">搜索</button>
</div>
</form>
<span>{{ error }}</span>
</div>
<form action="" method="post">
{% csrf_token %}
{{ study_record_formset.management_form }}
<div class="form-group pull-left">
<select name="action" id="action" class="form-control">
<option value="bulk_delete">批量删除</option>
</select>
</div>
<button class="btn btn-warning">Go</button>
{{ study_record_formset.errors }}
<table class="table table-striped table-hover table-bordered">
<thead>
<tr>
<th>
<input type="checkbox" id="select_all">选择
</th>
<th>序号</th>
<th>考勤</th>
<th>本节成绩</th>
<th>作业批语</th>
<th>某节课程</th>
<th>学员</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for study_record in study_record_formset %}
<tr>
<td>
<input type="checkbox" name="cids" value="{{ study_record.id }}
</td>
{{ study_record.id }}
<td>{{ forloop.counter }}</td>
<td>{{ study_record.attendance }}</td>
<td>{{ study_record.score }}</td>
<td>{{ study_record.homework_note }}</td>
<td>{{ study_record.instance.course_record }}</td>
<td class="hidden">{{ study_record.course_record }}</td>
<td>{{ study_record.instance.student }}</td> {# instance:当前记录的原始数据 而不是所有的客户 #}
<td class="hidden">{{ study_record.student }}</td> {# instance:当前记录的原始数据 而不是所有的客户 #}
<td>
{# <a href="{% url 'app04:delete_study_record' study_record.id %}"><i class="fa fa-remove"></i></a>#}
</td>
</tr>
{% endfor %}
</tbody>
</table>
<button class="btn btn-success">提交</button>
{{ page_html }}
{% endblock %}
</form>
遇到问题一:
需要在前端页面form表单中加入,类似于 {% csrf_token %}保证数据安全:
{{ study_record_formset.management_form }}
遇到问题二:
需要在前端页面form表单中加入,django要知道提交的具体是那一条数据:
{{ study_record.id }}
最终页面效果: