formset:适用于对多个表单进行操作,字段需要也可以用model中的表的字段来作为验证规则。

  modelformset:适用于对多个表单进行操作,字段需要也可以用model中的表的字段来作为验证规则,速度可能快一些(有待考证)

formset用法:

from django import forms
from django.forms import widgets 
from django.core.exceptions import ValidationError

class MultiPermissionForm(forms.Form):
    id = forms.IntegerField(
        widget=widgets.HiddenInput(),
        required=False
    )
    title = forms.CharField(
        widget=widgets.TextInput(attrs={'class': "form-control"})
    )
    url = forms.CharField(
        widget=widgets.TextInput(attrs={'class': "form-control"})
    )
    name = forms.CharField(
        widget=widgets.TextInput(attrs={'class': "form-control"})
    )
    menu_id = forms.ChoiceField(
        choices=[(None, '-----')],
        widget=widgets.Select(attrs={'class': "form-control"}),
        required=False,

    )

    pid_id = forms.ChoiceField(
        choices=[(None, '-----')],
        widget=widgets.Select(attrs={'class': "form-control"}),
        required=False,
    )

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['menu_id'].choices += models.Menu.objects.values_list('id', 'title')
        self.fields['pid_id'].choices += models.Permission.objects.filter(pid__isnull=True).exclude(
            menu__isnull=True).values_list('id', 'title')

    def clean_pid_id(self):
        menu = self.cleaned_data.get('menu_id')
        pid = self.cleaned_data.get('pid_id')
        if menu and pid:
            raise forms.ValidationError('菜单和根权限同时只能选择一个')
        return pid



from django.forms.models import formset_factory
from django.shortcuts import render, redirect

def add(request):
    """
      增加
    :param request:
    :return:
    """
    MultiPermissionFormSet = formset_factory(MultiPermissionForm, extra=0)
    if request.method == 'GET':
        form = MultiPermissionFormSet()
        return render(request,'list.html',{'form':form}
    form =  MultiPermissionFormSet(request.post)
    if form.is_valid():
        return redirect('url') 
    else:
         .........

def edit(request):
    """
      修改
    :param request:
    :return:
    """
    MultiPermissionFormSet = formset_factory(MultiPermissionForm, extra=0)
    if request.method == 'GET':
        form = MultiPermissionFormSet('数据')
        # formset是支持批量修改的所以 这里传入的数据一定要是可迭代对象,并且里面的 
          数据类型是字典或者对象
        return render(request,'list.html',{'form':form}
    form = MultiPermissionFormSet(request.post)
    if form.is_valid():
        return redirect('url') 
    else:
         .........
views.py
<div class="luffy-container">
        <form method="post" action="?type=generate">
            {% csrf_token %}
            {{ form.management_form }}
    # 这里一定要记得写这一步
            <div class="panel panel-default">
                <!-- Default panel contents -->
                <div class="panel-heading">
                    <i class="fa fa-binoculars" aria-hidden="true"></i> 待新建权限列表
                    <button class="right btn btn-primary btn-xs" style="padding: 2px 8px;margin: -3px;">
                        <i class="fa fa-save" aria-hidden="true"></i>
                        新建
                    </button>
                </div>
                <div class="panel-body" style="color: #9d9d9d;">
                    注意:路由系统中自动发现且数据库中不存在的路由。
                </div>

                <table class="table table-bordered">
                    <thead>
                    <tr>
                        <th>序号</th>
                        <th>名称</th>
                        <th>URL</th>
                        <th>别名</th>
                        <th>所属菜单</th>
                        <th>根权限</th>
                    </tr>
                    </thead>
                    <tbody>
                    {% for form in generate_formset %}
    
                        <tr>
                        <td style="vertical-align: middle;">{{ forloop.counter }}</td>
                        {% for field in form %}  #  这里在渲染标签的时候一定要渲染 id这个标签  这个很重要不然会报错  这里是写了两个fou循环 所以自动渲染了id标签
                            {% if forloop.first %}
                                <td class="hide">
                                    {% else %}
                                <td>
                            {% endif %}
                        {{ field }}<span style="color: firebrick;">{{ field.errors.0 }}</span>
                        </td>
                        {% endfor %}
                    {% endfor %}
                    </tbody>
                </table>
            </div>
        </form>
html

modelformset用法:

from django import forms
from app01.models import StudyRecord

class StudyRecordModelForm(forms.ModelForm):
    class Meta:
        model = StudyRecord
        fields = ['student','record','score','homework_note']


from django.shortcuts import render, redirect
from django.forms.models import modelformset_factory

def changelist_view(self,request):
        ccid = request.GET.get('ccid')
        model_formset_cls = modelformset_factory(models.StudyRecord,StudyRecordModelForm,extra=0)
        queryset = models.StudyRecord.objects.filter(course_record_id=ccid)
        if request.method == "GET":
            formset = model_formset_cls(queryset=queryset)
        # 这里UI定是个可迭代对象,因为modelformset是操作多表的,里面的数据类型可以为字典或者对象  
            return render(request,'study_record.html',{'formset':formset})

        formset = model_formset_cls(data=request.POST)
        # print(request.POST)
        if formset.is_valid():
            formset.save()
            return redirect('/stark/crm/studyrecord/list/?ccid=%s' %ccid )
        return render(request, 'study_record.html', {'formset': formset})
View Code
<div class="panel panel-default">
        <div class="panel-heading">学习记录</div>
        <div class="panel-body">
            <div style="width: 680px;margin: 0 auto;">
                <form method="post">
                    {% 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 }}  
                           # 这里只写了一层for循环,所以手动写字段,必须把id字段写上
                                <td>{{ form.instance.student }}</td>
                                <td>{{ form.record }} {{ form.record.errors.0 }}</td>
                                <td>{{ form.score }} {{ form.score.errors.0 }}</td>
                                <td>{{ form.homework_note }} {{ form.homework_note.errors.0 }}</td>
                            </tr>
                        {% endfor %}
                        </tbody>
                    </table>
                    <input type="submit" value="保存">
                </form>
            </div>
        </div>
    </div>
html

其实和modelform方法差不多,只不过是显示的时候可以直接修改,显示的select的那种模式

from django.forms import modelformset_factory

# 展示学习记录
def study_record_list(request, course_record_id):
    # 这是一个类  里面必填的两个参数,一个是model 一个是ModelForm
    FormSet = modelformset_factory(models.StudyRecord, StudyRecordForm, extra=0)  # extra=0 是把多的那一行去掉
    # formset 就是一组组的表单
    formset = FormSet(queryset=models.StudyRecord.objects.filter(course_record_id=course_record_id))

    if request.method == 'POST':
        formset = FormSet(request.POST)
        if formset.is_valid():
            formset.save()
            return redirect(reverse('study_record_list', args=(course_record_id,)))

    return render(request, 'study_record_list.html', {'formset': formset})

  要想在前端(study_record_list.html)展示效果,在前端页面中必须加上下面这些东西:

    下面的formset是后端传过来的

  

  

  

  对学习记录初始化的过程要进行批量操作, 但是有一个问题,比如我们已经初始化话过一次,但是后来了几个同学,这时候我们在进行初始化的时候就会报错,

  已经添加过的不能再添加, 这时候我们就能用到get_or_create(没有才创建)

    # 学习记录初始化
    def multi_init(self):
        course_record_ids = self.request.POST.getlist('ids')
        # 给一个课程记录下的所有学生添加学习记录
        for course_record_id in course_record_ids:
            # 拿到所有的学生
            course_record_obj = models.CourseRecord.objects.filter(pk=course_record_id).first()
            all_student = course_record_obj.re_class.customer_set.all().filter(status='studying')

            for stuedent in all_student:
                # models.StudyRecord.objects.create(student=stuedent,course_record_id=course_record_id)
                # get 获取,没有才创建  后来的学生也能听初始化 已经初始化过的不在创建 (用这种就行)
                models.StudyRecord.objects.get_or_create(student=stuedent, course_record_id=course_record_id)
                # 先更新 在创建
                # models.StudyRecord.objects.update_or_create(student=stuedent, course_record_id=course_record_id)

            # # 批量插入
            # study_record_list = []
            # for student in all_student:
            #     if models.StudyRecord.objects.filter(student=student,course_record_id=course_record_id).exists():
            #         continue
            #     obj = models.StudyRecord(student=student,course_record_id=course_record_id)
            #     study_record_list.append(obj)
            #     models.StudyRecord.objects.bulk_create(study_record_list,batch_size=10)  # 一次插10个

  显示的结果

  

modelforrmset示例:

from django import forms
from app01.models import StudentStudyRecord

class StudentStudyRecordModelForm(forms.ModelForm):
    class Meta:
        model = StudentStudyRecord
        fields = ["score", "homework_note"]
app01_forms.py
from django.shortcuts import render, redirect
from django.forms.models import modelformset_factory
from app01.app01_forms import StudentStudyRecordModelForm
from app01.models import StudentStudyRecord

class RecordScoreView(View):

    def get(self, request, class_study_record_id):

        model_formset_cls = modelformset_factory(model=StudentStudyRecord, form=StudentStudyRecordModelForm, extra=0)
        queryset = StudentStudyRecord.objects.filter(classstudyrecord=class_study_record_id)
        formset = model_formset_cls(queryset=queryset)
        return render(request, "student/record_score.html", locals())

    def post(self, request, class_study_record_id):
        model_formset_cls = modelformset_factory(model=StudentStudyRecord, form=StudentStudyRecordModelForm, extra=0)
        queryset = StudentStudyRecord.objects.filter(classstudyrecord=class_study_record_id)
        # print("request.POST",request.POST)
        formset = model_formset_cls(request.POST)
        if formset.is_valid():
            formset.save()
        # print(formset.errors)
        return redirect(request.path)
views.py
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.min.css">
</head>
<body>

 <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 }}
                           # 这里只写了一层for循环,所以手动写字段,必须把id字段写上
                                <td>{{ form.instance.student }}</td>
                                <td>{{ form.instance.get_record_display }} {{ form.record.errors.0 }}</td>
                                <td>{{ form.score }} {{ form.score.errors.0 }}</td>
                                <td>{{ form.homework_note }} {{ form.homework_note.errors.0 }}</td>
                            </tr>
                        {% endfor %}
                        </tbody>
                    </table>
                    <input type="submit" value="保存">
                </form>
            </div>
        </div>
    </div>

</body>
</html>
record_score.html
posted on 2019-11-04 16:00  始终不够啊  阅读(668)  评论(0编辑  收藏  举报