Django进阶--表单-模型表单

Django进阶–表单-模型表单

django版本:2.7.1

python版本:3.6

1. 简介

项目开发中,一个数据库模型通常需要有紧密关联的表单。举个栗子学生管理系统中:模型Student在前端页面中数据的增、改、查需要对应的表单。Django提供模型表单(ModelForm)将表单宇对应的模型紧密关联,使得代码更加灵活且维护方便。

2. 使用

2.1 流程

1. 创建模型表单类
from django import forms
class StudentForm(forms.ModelForm):
    class Meta:
        model = Student
        exclude = ['is_deleted'] #列表中的值是Student模型类的字段

class DetailForm(forms.ModelForm):
    class Meta:
        model = StuDetail
        exclude = ['student']  #表示除去【'student'】字段外,Student模型类中声明的其他字段都将添加进DetailForm
        #上式 <=> fields = ['qq', 'email'] fields关键字表示取出
  • 需要继承forms.ModelForm
  • 设置元类Meta,在里面声明需要的模型字段;
  • 相对于模型字段集合, ecclude表示除去,fields表示取出。

2. 字段类型

取自: 官方文档

模型领域表格字段
AutoField没有在表格中表示
BigAutoField没有在表格中表示
CharFieldCharField
DateFieldDateField
DateTimeFieldDateTimeField
EmailFieldEmailField
ForeignKeyModelChoiceField
ManyToManyFieldModelMultipleChoiceField
FileFieldFileField
TextFieldCharField,并带有widget=forms.Textarea参数
  • Model字段和表单字段有大量相似之处
  • ForeignKey被映射成为表单类的django.forms.ModelChoiceField,它的选项是一个模型的QuerySet,也就是可以选择的对象的列表,但是只能选择一个。
  • ManyToManyField被映射成为表单类的django.forms.ModelMultipleChoiceField,它的选项也是一个模型的QuerySet,也就是可以选择的对象的列表,但是可以同时选择多个,多对多嘛。

对于各别字段详解:

  • 如果模型字段设置blank=True,那么表单字段的required设置为False。 否则,required=True。
  • 表单字段的label属性根据模型字段的verbose_name属性设置,并将第一个字母大写。
  • 如果模型的某个字段设置了editable=False属性,那么它表单类中将不会出现该字段。道理很简单,都不能编辑了,还放在表单里提交什么?
  • 表单字段的help_text设置为模型字段的help_text
  • 如果模型字段设置了choices参数,那么表单字段的widget属性将设置成Select框,其选项来自模型字段的choices。选单中通常会包含一个空选项,并且作为默认选择。如果该字段是必选的,它会强制用户选择一个选项。 如果模型字段具有default参数,则不会添加空选项到选单中。

2.2 后台使用

from .models import Student, StuDetail
from .forms import RegisterForm, StudentForm, DetailForm

def new_edit(request, pk):		#模型Student和StuDetail是一对一关系
    stu = Student.objects.get(pk=pk)     		
    stu_form = StudentForm(instance=stu)		#填充表单
    try:
        detail_form = DetailForm(instance=stu.studetail)
    except:
        studetail = StuDetail()
        stu.studetail = studetail
        studetail.save()
        detail_form = DetailForm(instance=studetail)

    if request.method == 'POST':
        stu_form = StudentForm(request.POST)    #不指定instance将用data=request.POST填充表单
        detail_form = DetailForm(request.POST)
    context = {
        'section': '学生信息修改',
        'stu_form': stu_form,
        'detail_form': detail_form,
        'stu': stu,
    }
    return render(request, 'book/stu_newedit.html', context=context)

  • instance:指明填充实例。
  • 若要将表单内数据存入数据库,可直接使用model_form(即表单对象)的save()方法,会利用对性的模型类将数据刷入数据库。例如上例中:detail_form.save()

2.3 前端调用

{% load myfilters %}
    <form class="form-horizontal" action="{% url "book:newedit" stu.id %}" method="post">
        {% csrf_token %}
        {% for field in stu_form %}
            <div class="form-group ">
                <label class="control-label">{{ field.errors }}</label>
                <label class="col-sm-2 control-label">{{ field.label }}</label>
                <div class="col-sm-3 ">
					{{ field|addclass:'form-control' }}
                </div>
            </div>
        {% endfor %}
        <div style="margin-left: 25%">
            <button type="submit" class="btn btn-primary btn-lg active">提交</button>
        </div>
    </form>

{% endblock %}
  • 欲给field添加class(用于添加css样式),可使用过滤器或标签等
@register.filter(name='addclass')
def form_add_class(self, class_name):
    return self.as_widget(attrs={'class':class_name})
  • field.as_widget(attrs={属性名:属性值}),添加后该field对应的标签会添加class属性

3. 自定义验证

仅验证字段的合理性(field.clean)

3.1 模型

# models.py
class StuDetail(models.Model):
    qq = models.CharField('QQ号码', max_length=20, unique=True, default='', error_messages={'unique': 'QQ号码重复'})   # 添加错误信息
    phone = models.CharField('联系电话', max_length=20, unique=True, default='')
    student = models.OneToOneField(Student, on_delete=models.CASCADE)


3.2 验证

#views.py
def new_edit(request, pk):
    stu = Student.objects.get(pk=pk)

    if request.method == 'POST':
        stu_form = StudentForm(request.POST, instance=stu)
        detail_form = DetailForm(request.POST, instance=stu.studetail)
        if stu_form.is_valid() & detail_form.is_valid():
            stu_form.save()
            detail_form.save()
            return redirect(reverse('book:students'))
    else:
        stu_form = StudentForm(instance=stu)
        try:
            detail_form = DetailForm(instance=stu.studetail)
        except:
            studetail = StuDetail()
            stu.studetail = studetail
            studetail.save()
            detail_form = DetailForm(instance=studetail)

    context = {
        'section': '学生信息修改',
        'stu_form': stu_form,
        'detail_form': detail_form,
        'stu': stu,
        # 'colleges': colleges,
    }

    return render(request, 'book/stu_newedit.html', context=context)

3.3 结果

前端使用2.3展示的界面

在这里插入图片描述


  • 4
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值