Django ModelForm组件原理及用法详解


Posted in Python onOctober 12, 2020

这是一个神奇的组件,通过名字我们可以看出来,这个组件的功能就是把model和form组合起来。先来一个简单的例子来看一下这个东西怎么用:

比如我们的数据库中有这样一张学生表,字段有姓名,年龄,爱好,邮箱,电话,住址,注册时间等等一大堆信息,现在让你写一个创建学生的页面,你的后台应该怎么写呢?

首先我们会在前端一个一个罗列出这些字段,让用户去填写,然后我们从后天一个一个接收用户的输入,创建一个新的学生对象,保存起来。

其实,重点不是这些,而是合法性验证,我们需要在前端判断用户输入是否合法,比如姓名必须在多少字符以内,电话号码必须是多少位的数字,邮箱必须是邮箱的格式这些。当然可以一点一点手动写限制,各种判断,这毫无问题,不过比较麻烦。

我们现在有个更优雅(以后在Python相关的内容里,要多用“优雅”这个词,并且养成习惯)的方法:ModelForm

先来简单的,生硬的把它用上,再来加验证条件:

首先导入ModelForm

from django.forms import ModelForm

在视图函数中,定义一个类,比如就叫StudentList,这个类要继承ModelForm,在这个类中再写一个原类Meta(规定写法,并注意首字母是大写的)

在这个原类中,有以下属性(部分):

class StudentList(ModelForm):
  class Meta:
    model = models.Student #对应的Model中的类
    fields = "__all__"   #字段,如果是__all__,就是表示列出所有的字段
    exclude = None     #排除的字段
    labels = None      #提示信息
    help_texts = None    #帮助提示信息
    widgets = None     #自定义插件
    error_messages = None  #自定义错误信息
#error_messages用法:
    error_messages = {
      'name':{'required':"用户名不能为空",},
      'age':{'required':"年龄不能为空",},
    }

#widgets用法,比如把输入用户名的input框给为Textarea
#首先得导入模块
    from django.forms import widgets as wid #因为重名,所以起个别名
    widgets = {
      "name":wid.Textarea(attrs={"class":"c1"}) #还可以自定义属性
    }
#labels,自定义在前端显示的名字


labels= {
      "name":"用户名"
    }

如果想增加一个字段,就在class Meta 之前写这个字段。然后在url对应的视图函数中实例化这个类,把这个对象传给前端。

def student(request):
  if request.method == 'GET':
    student_list = StudentList()
    return render(request,'student.html',{'student_list':student_list})

然后前端只需要 {{ student_list.as_p }} 一下,所有的字段就都出来了,可以用as_p显示全部,也可以通过for循环这student_list,拿到的是一个个input框,现在我们就不用as_p,手动把这些input框搞出来,as_p拿到的页面太丑。

首先 for循环这个student_list,拿到student对象,直接在前端打印这个student,是个input框;student.label ,拿到数据库中每个字段的verbose_name ,如果没有设置这个属性,拿到的默认就是字段名;还可以通过student.errors.0 拿到错误信息,还有student.field,是拿到每个字段,如果这个字段是多对多字段,还能stuent.field.queryset,拿到所有关联的字段,还能stuent.field.queryset.model,拿到所有关联的字段的类。有了这些,我们就可以通过bootstrap,自己拼出来想要的样式了

比如:

<body>
  <div class="container" >
    <h1>student</h1>
    <form method="POST" novalidate>
      {% csrf_token %}
{#      {{ student_list.as_p }}#}
      {% for student in student_list %}
        <div class="form-group col-md-6">
         {# 拿到数据字段的verbose_name,没有就默认显示字段名 #}
          <label class="col-md-3 control-label">{{ student.label }}</label>
          <div class="col-md-9" style="position: relative;">{{ student }}</div>
        </div>
      {% endfor %}

      <div class="col-md-2 col-md-offset-10">
        <input type="submit" value="提交" class="btn-primary">
      </div>
    </form>
  </div>
</body>

现在还缺一个input框的form-control样式,可以考虑在后台的widget里面添加。

比如这样:

from django.forms import widgets as wid #因为重名,所以起个别名
    widgets = {
      "name":wid.TextInput(attrs={'class':'form-control'}),
      "age":wid.NumberInput(attrs={'class':'form-control'}),
      "email":wid.EmailInput(attrs={'class':'form-control'})
    }

当然也可以在js中,找到所有的input框,加上这个样式,也行。

保存数据的时候,不用挨个取数据了,只需要save一下。

def student(request):

  if request.method == 'GET':
    student_list = StudentList()
    return render(request,'student.html',{'student_list':student_list})
  else:
    student_list = StudentList(request.POST)
    if student_list.is_valid():
      student_list.save()
    return redirect(request,'student_list.html',{'student_list':student_list})

编辑数据:

如果不用ModelForm,编辑的时候得显示之前的数据吧,还得挨个取一遍值,如果ModelForm,只需要加一个instance=obj(obj是要修改的数据库的一条数据的对象)就可以得到同样的效果。

保存的时候要注意,一定要注意有这个对象(instance=obj),否则不知道更新哪一个数据。

代码示例:

from django.shortcuts import render,HttpResponse,redirect
from django.forms import ModelForm
# Create your views here.
from app01 import models

def test(request):

  # model_form = models.Student
  model_form = models.Student.objects.all()
  return render(request,'test.html',{'model_form':model_form})


class StudentList(ModelForm):
  class Meta:
    model = models.Student #对应的Model中的类
    fields = "__all__"   #字段,如果是__all__,就是表示列出所有的字段
    exclude = None     #排除的字段
    labels = None      #提示信息
    help_texts = None    #帮助提示信息
    widgets = None     #自定义插件
    error_messages = None  #自定义错误信息
#error_messages用法:
    error_messages = {
      'name':{'required':"用户名不能为空",},
      'age':{'required':"年龄不能为空",},
    }

#widgets用法,比如把输入用户名的input框给为Textarea
#首先得导入模块
    from django.forms import widgets as wid #因为重名,所以起个别名
    widgets = {
      "name":wid.Textarea
    }
#labels,自定义在前端显示的名字
    labels= {
      "name":"用户名"
    }
def student(request):

  if request.method == 'GET':
    student_list = StudentList()
    return render(request,'student.html',{'student_list':student_list})
  else:
    student_list = StudentList(request.POST)
    if student_list.is_valid():
      student_list.save()
    return render(request,'student.html',{'student_list':student_list})

def student_edit(request,pk):
  obj = models.Student.objects.filter(pk=pk).first()
  if not obj:
    return redirect('test')
  if request.method == "GET":
    student_list = StudentList(instance=obj)
    return render(request,'student_edit.html',{'student_list':student_list})

  else:
    student_list = StudentList(request.POST,instance=obj)
    if student_list.is_valid():
      student_list.save()
    return render(request,'student_edit.html',{'student_list':student_list})

使用ModelForm编辑数据

对于验证规则,很多浏览器都比较智能,会自动帮我们做一些验证,可以在form表单上加 novalidate 属性就可以不让浏览器为我们做验证

ModelForm还支持所有form的功能,比如钩子,所以我们就可以通过钩子来自定义验证规则

写法和forms的写法一样:

class AuthorForm(forms.ModelForm):
  class Meta:
    model = Author
    fields = ('name', 'title')

  def clean_name(self):
    if ...
       return self.clean_data['name']
    else:
       raise ValidationError(‘sdgsadga')
    ...

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python实现的一个找零钱的小程序代码分享
Aug 25 Python
Python实现的数据结构与算法之队列详解
Apr 22 Python
Python 搭建Web站点之Web服务器网关接口
Nov 06 Python
Python查看微信撤回消息代码
Jun 07 Python
Python中安装easy_install的方法
Nov 18 Python
Django框架使用mysql视图操作示例
May 15 Python
Python自定义聚合函数merge与transform区别详解
May 26 Python
python脚本第一行如何写
Aug 30 Python
Python SQLAlchemy库的使用方法
Oct 13 Python
selenium学习教程之定位以及切换frame(iframe)
Jan 04 Python
关于Python中进度条的六个实用技巧分享
Apr 05 Python
Python中使用tkFileDialog实现文件选择、保存和路径选择
May 20 Python
Python ConfigParser模块的使用示例
Oct 12 #Python
python修改微信和支付宝步数的示例代码
Oct 12 #Python
教你如何用python操作摄像头以及对视频流的处理
Oct 12 #Python
Django限制API访问频率常用方法解析
Oct 12 #Python
Python confluent kafka客户端配置kerberos认证流程详解
Oct 12 #Python
Django如何使用asyncio协程和ThreadPoolExecutor多线程
Oct 12 #Python
使用Python中tkinter库简单gui界面制作及打包成exe的操作方法(二)
Oct 12 #Python
You might like
解析htaccess伪静态的规则
2013/06/18 PHP
解决PHP4.0 和 PHP5.0类构造函数的兼容问题
2013/08/01 PHP
php环境下利用session防止页面重复刷新的具体实现
2014/01/09 PHP
重新认识php array_merge函数
2014/08/31 PHP
php类自动装载、链式操作、魔术方法实现代码
2017/07/23 PHP
php文件上传原理与实现方法详解
2019/12/20 PHP
Node.js中防止错误导致的进程阻塞的方法
2016/08/11 Javascript
Angularjs 动态添加指令并绑定事件的方法
2017/04/13 Javascript
JS按条件 serialize() 对应标签的使用方法
2017/07/24 Javascript
JS滚轮控制图片缩放大小和拖动的实例代码
2018/11/20 Javascript
解决vue中axios设置超时(超过5分钟)没反应的问题
2020/09/04 Javascript
[01:38]完美世界DOTA2联赛PWL S3 集锦第四期
2020/12/21 DOTA
用Python的SimPy库简化复杂的编程模型的介绍
2015/04/13 Python
关于Python中浮点数精度处理的技巧总结
2017/08/10 Python
Python判断一个三位数是否为水仙花数的示例
2018/11/13 Python
python读取与处理netcdf数据方式
2020/02/14 Python
python3中sorted函数里cmp参数改变详解
2020/03/12 Python
Python绘图之二维图与三维图详解
2020/08/04 Python
HTML5使用ApplicationCache接口实现离线缓存技术解决离线难题
2012/12/13 HTML / CSS
详解基于canvas的视频遮罩插件
2018/01/04 HTML / CSS
用canvas做一个DVD待机动画的实现代码
2019/04/12 HTML / CSS
用canvas显示验证码的实现
2020/04/10 HTML / CSS
销售人员自我评价怎么写
2013/09/19 职场文书
硕士研究生自我鉴定范文
2013/12/27 职场文书
党员党性分析材料
2014/02/17 职场文书
新闻学专业大学生职业生涯规划范文
2014/03/02 职场文书
遗嘱公证书标准样本
2014/04/08 职场文书
四年级学生评语大全
2014/04/21 职场文书
推荐信模板
2014/05/09 职场文书
普通话宣传标语
2014/06/26 职场文书
港澳通行证委托书怎么写
2014/08/02 职场文书
入党现实表现材料
2014/12/23 职场文书
男方家长婚礼致辞
2015/07/27 职场文书
大学生社会实践感想
2015/08/11 职场文书
python 统计代码耗时的几种方法分享
2021/04/02 Python
vue cli4中mockjs在dev环境和build环境的配置详情
2022/04/06 Vue.js