Django之批量生成数据和modelformset

一.批量生成数据

需求:点击【批量生成学习记录】后将下面的课程记录生成学习记录

在这里插入图片描述

表结构:

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 }}

最终页面效果:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_39253370/article/details/106259811