一.课程记录
需求如下图中:如深圳python10期的课程,有120天的课(每天讲了什么有无作业)。每一个学生都有每一天课程的一个学习记录。而系统到此只写到班级列表,那此时我想看下这个课程里,都有哪些课程记录,怎么做?
  
如下图:点一下就跳转课程的记录页面
 
所以写这个课程视图记录函数时,一定得告诉看的是哪个课程的。

(1)crm_urls.py:先从url开始添加:cbv
# 因为查询课程记录 一定是指定查询某个班级的上课记录 url(r'^course_record_list/(?P<class_id>\d+)/$', mei_views.CourseListView.as_view(), name='course_record_list'), # 添加课程记录 url(r'^add_course_record/(?P<class_id>\d+)/$', mei_views.course_record, name='add_course_record'), url(r'^edit_course_record/(?P<course_record_id>\d+)/$', mei_views.course_record, name='edit_course_record'),
(2)mei_views.py中:
get请求方法中,除了有request还要得只知道哪个班级的--通过re_class字段去数据库拿哪个课程的所有记录,所以还要有班级id--所以url中也要分组命名去捕获一个参数--(?P<class_id>\d+)--因为查询课程记录一定是指定查询某个班级的上课记录。
一点提交是post请求。并给添加按钮a标签加一个当前的url,为了添加完还得跳回来。
from django.http import QueryDict from crm.models import ClassList, CourseRecord from crm.forms import ClassListForm,ConsultRecordForm,CourseRecordForm #课程记录 class CourseListView(views.View): def get(self,request,class_id): #根据班级id查询出所有上课记录 query_set = CourseRecord.objects.filter(re_class_id=class_id)#re_class是外键有一划线_id查自己表,__id是跨表 current_url = request.get_full_path()#这是拿到跳转前的url qd = QueryDict(mutable=True) qd['next'] = current_url #就是跳转前的url字符串 return render(request, 'course_list.html', {'course_record_list': query_set, 'next_url': qd.urlencode(), 'class_id': class_id}) def course_record(request, class_id=None, course_record_id=None): class_obj = ClassList.objects.filter(id=class_id).first() edit_obj = CourseRecord.objects.filter(id=course_record_id).first()#获取要编辑的对象 form_obj = CourseRecordForm(instance=edit_obj, initial={'re_class': class_obj})#生成一个form对象 if request.method == 'POST': form_obj = CourseRecordForm(request.POST)#点提交后生成一个带数据的form对象 if form_obj.is_valid(): form_obj.save()#添加成功后跳转到当前班级的上课记录列表页 next_url = request.GET.get('next', '/crm/class_list/')#从url中取不到netxt参数就跳到默认班级列表页url return redirect(next_url) return render(request,'consult_record.html',{'form_obj':form_obj,'edit_id':course_record_id})
(3)course_list.html:和班级页面一样是表格的形式
迭代mei_views中的课程记录--course_record_list.
我想要的是有入口进去此页面中,点某班级就进入到它的课程记录中--所以在class_list.html中给每一课程加a标签--a标签中要提供课程记录url和接收班级id。
一加添加编辑按钮。给添加按钮 a标签传?{{netx_url}}跳转前的url。
{% extends 'base.html' %}
{% block page-main %}
    <h2 class="sub-header">课程记录列表</h2>
    <div class="col-md-12">
        <a href="{% url 'add_course_record' class_id %}?{{ next_url }}" class="btn btn-success btn-sm">添加</a>
        <div class="col-md-4 pull-right">
            <form action="" method="get" enctype="application/x-www-form-urlencoded">
                <div class="input-group">
                    <input type="text" name="query" class="form-control" placeholder="Search for...">
                    <span class="input-group-btn">
        <button class="btn btn-default" type="submit">搜呀</button>
      </span>
                </div><!-- /input-group -->
            </form>
        </div>
    </div>
    <form action="" method="post">
        {% csrf_token %}
        <div class="col-md-3" style="margin: 5px 0">
            <div class="input-group">
                <select class="form-control" name="action">
                    <option value="">---------</option>
                    <option value="multi_init">初始化学习记录</option>
                    <option value="delete">删除</option>
                </select>
                <div class="input-group-btn">
                    <button type="submit" class="btn btn-primary">提交</button>
                </div>
            </div>
        </div>
        <div class="col-md-12">
            <div class="table-responsive">
                <table class="table table-striped table-bordered">
                    <thead>
                    <tr>
                        <th>选择</th>
                        <th>#</th>
                        <th>课程标题</th>
                        <th>上课时间</th>
                        <th>作业</th>
                        <th>授课老师</th>
                        <th>操作</th>
                    </tr>
                    </thead>
                    <tbody>
                    {% for course_record in course_record_list %}{# 迭代mei_views中的课程记录 #}
                        <tr>
                            <td><input type="checkbox" name="cid" value="{{ course_record.id }}"></td>
                            <td>{{ forloop.counter }}</td>
                            <td>{{ course_record.course_title }}</td>
                            <td>{{ course_record.date }}</td>
                            <td>{{ course_record.has_homework }}</td>
                            <td>{{ course_record.teacher.name }}</td>
                            <td><a href="{% url 'edit_course_record' course_record.id %}"><i class="fa fa-edit" aria-hidden="true"></i></a>
                            </td>
                        </tr>
                    {% endfor %}
                    </tbody>
                </table>
                <div>
                    {{ page_html|safe }}
                </div>
            </div>
        </div>
    </form>
{% endblock %}
(4)forms.py中:
  在课程记录页面点添加,即添加课程记录表的数据,所以用到form表单。那是字段太多,懒得挨个写,所以写一modelform.
from crm.models import UserProfile, Customer, ConsultRecord,Enrollment,ClassList,CourseRecord # 课程记录 class CourseRecordForm(BootstrapBaseForm): class Meta: model = CourseRecord fields = '__all__'
(5)course_record.html添加编辑页面中:
{% extends 'base.html' %}
{% block page-main %}
    <div>
        <h2 class="text-center">{% if edit_id %}编辑上课记录{% else %}添加上课记录{% endif %}</h2>
        <form class="form-horizontal" action="" method="post" novalidate>
            {% csrf_token %}
            {% for field in form_obj %}
                <div class="form-group {% if  field.errors.0 %}has-error{% endif %}">
                    <label for="{{ field.id_for_label }}" class="col-sm-2 control-label">{{ field.label }}</label>
                    <div class="col-sm-10">
                        {{ field }}
                        <span class="help-block">{{ field.errors.0 }}</span>
                    </div>
                </div>
            {% endfor %}
            <div class="form-group">
                <div class="col-sm-offset-2 col-sm-10">
                    <button type="submit" class="btn btn-default">提交</button>
                </div>
            </div>
        </form>
    </div>
{% endblock %}
{% block page-js %}
    {% load static %}
    <script src="{% static 'jquery.js' %}"></script>
{% endblock %}
这样就实现了如下图:

 
注意这里的models.py中我是定义了show_name方法把课程和节次字段拼接了并传给course_list.html在一个字段展示。
def show_name(self): return '{}--day{}'.format(self.re_class,self.day_num)
所以在course_list.html中要添加如下两行:
<th>课程节次</th>
<td>{{ course_record.show_name }}</td>
二.学习记录

之前写的form都是一条记录一个form,现在呢一个班的课程记录中的一天要给班的每一个人生成一个考勤记录上(50个学生就有50条课程记录),那这样就麻烦了.上图中就是每一节课都要对应生成很多个上课记录
需求如下图中:我点day1这一天的课程记录时会弹出一个页面展示所有学生的学习记录(谁出勤,跳课..)
  
 
但是day1这天课程中都得有每一个学生的上课记录,那我添加50次(50个学生),这样不方便。那我想的是有一个初始化考勤的操作,一点提交,相当于在后端是去数据库中把此课程的所有学生都找出来给它们生成一个默认的批量的初始考勤表出来---一条学习记录是对应一个课程,而课程中能拿到班级re_class,而班级中反向查询能拿到所有的学生。也就是学习记录:先查课程记录再查班级再找到所有学生,那学习记录表中student和课程记录字段就有了。所以我初始化学习记录,也就是day1这一天的所有学生学习记录都创建好了,接下来在上面做一个考勤谁迟到了勾一下即可。--就是上图中我在day1课程记录前做一勾选--并有一批量初始化的操作,一点提交就把day1这个课程对应的所有的学生都给它们初始化一份新的学习记录--这个动作的添加方式和变私户公户一样--一点提交是往当前的url发送post请求把当前上课记录的id传给此id,我在后端拿到这个id找到这个课程再找到所有已报名的学生然后把它们都初始化一下。
用代码批量初始化,把没有出勤的改下就行。实现批量:有一个checkbox和select标签然后用一form表单把里边的表格和此两按钮标签包起来即可---一点提交时它会携带着你勾选的哪一课程条记action(select标签选中的值)--一点提交往当前url(/crm/course_record_list/1)发post请求,这个1就是class_id。
(1)crm_urls.py中:
# 课程记录 # 因为查询课程记录 一定是指定查询某个班级的上课记录 url(r'^course_record_list/(?P<class_id>\d+)/$', mei_views.CourseListView.as_view(), name='course_record_list'), # 添加课程记录 url(r'^add_course_record/(?P<class_id>\d+)/$', mei_views.course_record, name='add_course_record'), url(r'^edit_course_record/(?P<course_record_id>\d+)/$', mei_views.course_record, name='edit_course_record'), # 学习记录 url(r'^study_record_list/(?P<course_record_id>\d+)/$', mei_views.study_record_
(1)course_list.html中:
a标签传一课程id就能拿到所有的学生记录。
{% extends 'base.html' %}
{% block page-main %}
    <h2 class="sub-header">客户列表</h2>
    <div class="col-md-12">
        <a href="{% url 'add_customer' %}?next={{ request.get_full_path }}" class="btn btn-success btn-sm">添加</a>
        <div class="col-md-4 pull-right">
            <form action="" method="get" enctype="application/x-www-form-urlencoded">
                <div class="input-group">
                    <input type="text" name="query" class="form-control" placeholder="Search for...">
                    <span class="input-group-btn">
        <button class="btn btn-default" type="submit">搜呀</button>
      </span>
                </div><!-- /input-group -->
            </form>
        </div>
    </div>
    <form action="" method="post">
        {% csrf_token %}
        <div class="col-md-3" style="margin: 5px 0">
            <div class="input-group">
                <select class="form-control" name="action">
                    <option value="">---------</option>
                    <option value="to_public">变为公户</option>
                    <option value="to_private">变为私户</option>
                    <option value="delete">删除</option>
                </select>
                <div class="input-group-btn">
                    <button type="submit" class="btn btn-primary">提交</button>
                </div>
            </div>
        </div>
        <div class="col-md-12">
            <div class="table-responsive">
                <table class="table table-striped table-bordered">
                    <thead>
                    <tr>
                        <th style="width: 20px">选择</th>
                        <th style="width: 20px">#</th>
                        <th style="width: 80px">QQ</th>
                        <th style="width: 80px">QQ昵称</th>
                        <th style="width: 60px">姓名</th>
                        <th style="width: 80px">电话</th>
                        <th style="width: 90px">客户来源</th>
                        <th style="width: 120px">咨询课程</th>
                        <th style="width: 60px">招生老师</th>
                        <th style="width: 60px">班级类型</th>
                        <th style="width: 60px">状态</th>
                        <th style="width: 100px">咨询日期</th>
                        <th style="width: 120px!important;">已报班级</th>
                        <th style="width: 120px!important;">沟通记录</th>
                        <th style="width: 120px!important;">报名</th>
                        <th style="width: 20px!important;">操作</th>
                    </tr>
                    </thead>
                    <tbody>
                    {% for customer in customer_list %}
                        <tr>
                            <td><input type="checkbox" name="cid" value="{{ customer.id }}"></td>
                            <td>{{ forloop.counter }}</td>
                            <td>{{ customer.qq }}</td>
                            <td>{{ customer.qq_name }}</td>
                            <td>{{ customer.name }}</td>
                            <td>{{ customer.phone|default:'暂无' }}</td>
                            <td>{{ customer.get_source_display }}</td>
                            <td>{{ customer.course }}</td>
                            <td>{{ customer.consultant }}</td>
                            <td>{{ customer.get_class_type_display }}</td>
                            <td>{{ customer.show_status }}</td>
                            <td>{{ customer.date|date:'Y-m-d' }}</td>
                            <td>{{ customer.show_class_list|default:'暂无' }}</td>
                            <td><a href="{% url 'consult_record' cid=customer.id %}">查看</a></td>
                            <td>
                                <a href="{% url 'add_enrollment' customer.id %}">添加</a> |
                                <a href="{% url 'enrollment_list' customer.id %}">查看</a>
                            </td>
                            <td><a href="{% url 'edit_customer' customer.id %}?{{ next_url }}"><i class="fa fa-edit"
                                                                                   aria-hidden="true"></i></a></td>
                        </tr>
                    {% endfor %}
                    </tbody>
                </table>
                <div>
                    {{ page_html|safe }}
                </div>
            </div>
        </div>
    </form>
{% endblock %}
(2)forms.py中:
# 课程记录 class CourseRecordForm(BootstrapBaseForm): class Meta: model = CourseRecord fields = '__all__'
(2)mei_views.py中:
在课程记录视图中接收一个post请求
# 班主任相关的视图都放在这里 from django import views from django.shortcuts import render, redirect,HttpResponse from crm.models import ClassList, CourseRecord,StudyRecord from crm.forms import ClassListForm,ConsultRecordForm,CourseRecordForm,StudyRecordForm from django.urls import reverse from django.http import QueryDict class ClassListView(views.View): def get(self, request): query_set = ClassList.objects.all() return render(request, 'class_list.html', {'class_list': query_set}) # 新增和编辑班级 def op_class(request, edit_id=None): edit_obj = ClassList.objects.filter(id=edit_id).first() form_obj = ClassListForm(instance=edit_obj) if request.method == 'POST': form_obj = ClassListForm(request.POST, instance=edit_obj) if form_obj.is_valid(): form_obj.save() return redirect(reverse('class_list')) return render(request, 'op_class.html', {'form_obj': form_obj, 'edit_id': edit_id}) #课程记录 class CourseListView(views.View): def get(self,request,class_id): #根据班级id查询出所有上课记录 query_set = CourseRecord.objects.filter(re_class_id=class_id)#re_class是外键有一划线_id查自己表,__id是跨表 current_url = request.get_full_path()#这是拿到跳转前的url qd = QueryDict(mutable=True) qd['next'] = current_url #就是跳转前的url字符串 return render(request, 'course_list.html', {'course_record_list': query_set, 'next_url': qd.urlencode(), 'class_id': class_id}) def post(self,request,class_id):#form表单中post请求提交过来 #1.从post提交过来的数据里找到action动作和勾选的课程记录id cid = request.POST.getlist('cid') action = request.POST.get('action') #2.利用反射执行指定的动作 if hasattr(self,'_{}'.format(action)):#如果有跟action同名的方法 ret = getattr(self,'_{}'.format(action))(cid)#就执行action有的方法并传cid else: return HttpResponse('没有此操作') if ret:#如果你action中有内部的私有化方法有返回值的话,就返回这个值 return ret else: return redirect(reverse('course_record_list',kwargs={'class_id':class_id})) def _mult_init(self, cid): #3根据cid找到要初化学习记录的那些课程 courser_objs = CourseRecord.objects.filter(id__in=cid) #4针对每个课程挨个初始化学习记录 #4.1初始化学习记录即创建学习记录:需要课程记录cid和学生(re_class反向查找能拿到此班级所有学生) for course_record in courser_objs: all_student = course_record.re_class.customer_set.all() #拿到学生后每一个学生都创建一个当前课程的学习记录--不用for循环了因为前面已经有,用生成器生成式sql效率高 studentreord_objs = (StudyRecord(course_record=course_record,student=student) for student in all_student) #统一提交一次就行:即一个课程提交一次,不用所有课程一次提交 StudyRecord.objects.bulk_create(studentreord_objs) return HttpResponse('初始化好了') def course_record(request, class_id=None, course_record_id=None): class_obj = ClassList.objects.filter(id=class_id).first() edit_obj = CourseRecord.objects.filter(id=course_record_id).first()#获取要编辑的对象 form_obj = CourseRecordForm(instance=edit_obj, initial={'re_class': class_obj})#生成一个form对象 if request.method == 'POST': form_obj = CourseRecordForm(request.POST)#点提交后生成一个带数据的form对象 if form_obj.is_valid(): form_obj.save()#添加成功后跳转到当前班级的上课记录列表页 next_url = request.GET.get('next', '/crm/class_list/')#从url中取不到netxt参数就跳到默认班级列表页url return redirect(next_url) return render(request,'consult_record.html',{'form_obj':form_obj,'edit_id':course_record_id}) # 学习记录列表 def study_record_list(request, course_record_id):#捕获id路由中命名分组 # 拿到这一个课程记录的所有同学的学习记录 query_set = StudyRecord.objects.filter(course_record_id=course_record_id) return render(request, 'study_record_list.html', {'formset_obj': query_set})
(3)study_record_list.html:
{% extends 'base.html' %}
{% block page-main %}
<h2 class="sub-header">学习记录表</h2>
<div class="col-md-12">
    <div class="col-md-4 pull-right">
        <form action="" method="get" enctype="application/x-www-form-urlencoded">
            <div class="input-group">
                <input type="text" name="query" class="form-control" placeholder="Search for...">
                <span class="input-group-btn">
                    <button class="btn btn-default" type="submit">搜呀</button>
                </span>
            </div><!-- /input-group -->
        </form>
    </div>
</div>
<form action="" method="post">
    {% csrf_token %}
    {{ formset_obj.management_form }}
    <div class="col-md-3" style="margin: 5px 0">
    </div>
    <div class="col-md-12">
        <div class="table-responsive">
            <table class="table table-striped table-bordered">
                <thead>
                <tr>
                    <th style="width: 20px">#</th>
                    <th style="width: 80px">姓名</th>
                    <th style="width: 80px">考勤</th>
                    <th style="width: 80px">成绩</th>
                    <th style="width: 80px">作业</th>
                </tr>
                </thead>
                <tbody>
                {% for form_obj in formset_obj %}
                <tr>
                    {{ form_obj.id }}
                    <td>{{ forloop.counter }}</td>
                    <td style="display: none">{{ form_obj.student }}</td>
                    <td>{{ form_obj.instance.student.name }}</td>
                    <td>{{ form_obj.attendance }}</td>
                    <td>{{ form_obj.score }}</td>
                    <td>{{ form_obj.homework_note }}</td>
                </tr>
                {% endfor %}
                </tbody>
            </table>
            <div>
                {{ page_html|safe }}
            </div>
            <button class="btn btn-success" type="submit">保存</button>
        </div>
    </div>
</form>
{% endblock %}
这样就实现了在班级页面点击某个课程进入课程记录列表页面再点击某个记录就能展示出该天课程记录的所有学生的情况表如下图:

 

二. formset
上图效果学习记录表页面中:我希望如考勤那列有个下拉框(逃课,迟到..),我点某些学生点一个保存就行,所以得在此页面上支持一个编辑功能---formset。因为上图学习记录表页面中如果每个学生的学习记录支持当前可编辑的话,就是一个学生的学习记录生成一个form表单,那我50个学生要50个表单--麻烦。当需要多个form时用formset(form的集合),如下图中:当点保存时把整个班的情况统一保存可

(1)forms.py中:
  
# 学习记录的 class StudyRecordForm(BootstrapBaseForm): class Meta: model = StudyRecord fields = ['student', 'attendance', 'score', 'homework_note']#只需要这些字段
(2)mei_views.py:中
导入formset类的modelformset_factory工厂方法它造出来的是一个fformset类,
from django.forms import modelformset_factory # 学习记录列表 def study_record_list(request, course_record_id):#捕获id路由中命名分组 FormSet = modelformset_factory(StudyRecord,StudyRecordForm,extra=0)#它接收model(用哪个模型)和form,返回值是一个类,extra是在这个页面额外存放几个form # 拿到这一个课程记录的所有同学的学习记录 query_set = StudyRecord.objects.filter(course_record_id=course_record_id) formset_obj = FormSet(queryset=query_set) # 实例化就是把查到的每一个学习记录form都呈现出来 if request.method == 'POST': formset_obj = FormSet(request.POST,queryset=query_set) if formset_obj.is_valid(): formset_obj.save() return render(request, 'study_record_list.html', {'formset_obj': formset_obj})
(4)study_record_list.html中:
{% extends 'base.html' %}
{% block page-main %}
<h2 class="sub-header">学习记录表</h2>
<div class="col-md-12">
    <div class="col-md-4 pull-right">
        <form action="" method="get" enctype="application/x-www-form-urlencoded">
            <div class="input-group">
                <input type="text" name="query" class="form-control" placeholder="Search for...">
                <span class="input-group-btn">
                    <button class="btn btn-default" type="submit">搜呀</button>
                </span>
            </div><!-- /input-group -->
        </form>
    </div>
</div>
<form action="" method="post">
    {% csrf_token %}
    {{ formset_obj.management_form }} {# 这是告诉form管理类你提交数据时总共有多少个form要提交---这行是必须的 #}
    <div class="col-md-3" style="margin: 5px 0">
    </div>
    <div class="col-md-12">
        <div class="table-responsive">
            <table class="table table-striped table-bordered">
                <thead>
                <tr>
                    <th style="width: 20px">#</th>
                    <th style="width: 80px">姓名</th>
                    <th style="width: 80px">考勤</th>
                    <th style="width: 80px">成绩</th>
                    <th style="width: 80px">作业</th>
                </tr>
                </thead>
                <tbody>
                {% for form_obj in formset_obj %}{# 这个formset_obj里边就是一个个小的form对象 #}
                <tr>
                    {{ form_obj.id }}{# 把一个个小form对象中某字段拿出来 #}
                    <td>{{ forloop.counter }}</td>
                    <td style="display: none">{{ form_obj.student }}</td> {# 把student字段隐藏,这样form提交时就不会提交它 #}
                    <td>{{ form_obj.instance.student.name }}</td>{# form表单中instance是当前这行数据的实例,把它的name字段取出来当默认 #}
                    <td>{{ form_obj.attendance }}</td>
                    <td>{{ form_obj.score }}</td>
                    <td>{{ form_obj.homework_note }}</td>
                </tr>
                {% endfor %}
                </tbody>
            </table>
            <div>
                {{ page_html|safe }}
            </div>
            <button class="btn btn-success" type="submit">保存</button>
        </div>
    </div>
</form>
{% endblock %} 
                    
                
                
            
        
浙公网安备 33010602011771号