Django之ModelForm

作者:@skyflask
转载本文请注明出处:https://www.cnblogs.com/skyflask/p/9710809.html


目录

一、Model+Form(原生写法)
二、Model+Form模块
三、ModelForm模块
四、三种方式比较

 顾名思义,Model + Form == ModelForm。model和form的合体,所以有以下功能:

  • 验证数据字段(Form的功能)
  • 数据库操作(Model的功能)

model有操作数据库的字段,form验证也有那几个字段,虽然耦合度降低,但是代码是有重复的。如果利用model里的字段,那是不是form里的字段就不用写了。

在了解ModelForm模块之前,我们来看看Model+Form原生写法以及Model+Form模块,最后来看看三者的区别及优势。

一、Model+Form(原生写法)

1、models.py文件

1
2
3
4
5
6
7
8
class UserType(models.Model):
    caption = models.CharField(max_length=32)
 
class User(models.Model):
    username = models.CharField(max_length=32)
    email = models.EmailField(max_length=32)
    #指定关系一对多,指定和哪张表建立一对多,指定和哪个字段关联       
    user_type = models.ForeignKey(to='UserType',to_field='id')

  


2、前端myform.py文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
     <form action="/myform/" method="POST">
        {% csrf_token %}
        {{ msg }}<br/>
         <label for="id_username">Username:</label>
         <input type="text" id="id_username" name="username"/>
         <br/>
         <label for="id_email">Email:</label>
         <input type="text" id="id_email" name="email"/>
         <br/>
         <select name="user_type">
             {% for t in user_type %}
              <option name ="{{ t.caption }}">{{ t.caption }}</option>
             {% endfor %}
        </select>
 
         <input type="submit" value="提交">
    </form>
    <br/>
   <table>
       <th>
           <tr>用户名</tr>
           <tr>邮箱</tr>
           <tr>角色</tr>
       </th>
       {% for obj in new_obj %}
       <tr>
           <td>{{ obj.username }}</td>
           <td>{{ obj.email }}</td>
           <td>{{ obj.user_type.caption }}</td>
       </tr>
        {% endfor %}
   </table>
</body>
</html>

  

3、views.py文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
def myform(request):
    if request.method == 'GET':
        obj = models.User.objects.all()
        user_type = models.UserType.objects.all()
        return render(request,'myform.html',{'new_obj':obj,'user_type':user_type})
    elif request.method == 'POST':
        msg = ''
        username = request.POST.get('username')
        email = request.POST.get('email')
        u_type = request.POST.get('user_type')
 
        user_type = models.UserType.objects.all()
        obj = models.User.objects.all()
        c = models.User.objects.filter(username=username, email=email).count()
        ut  = models.UserType.objects.filter(caption=u_type).first()
 
        if c>0:
            msg = '用户名和邮箱重复!'
            return render(request, 'myform.html', {'obj': obj,'msg':msg,'user_type':user_type})
        elif not username or not email:
            msg = '用户名和邮箱不能为空!'
            return render(request, 'myform.html', {'obj': obj, 'msg':msg,'user_type':user_type})
        else:
            msg = '增加记录成功!'
            models.User.objects.create(username=username, email=email, user_type=ut)
            return render(request, 'myform.html', {'obj': obj,'msg':msg,'user_type':user_type})

  

4、效果图

 

 

 

二、Model+Form模块

1、models.py文件

1
同上面的models.py文件

 

2、forms.py文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#coding:utf-8
from django import forms
from django.forms import fields
from app01 import models
from django.core.exceptions import ValidationError
 
class UserInfoForm(forms.Form):
    username = fields.CharField(max_length=32)
    email = fields.EmailField(max_length=32)
    user_type = fields.ChoiceField(
        choices=models.UserType.objects.values_list('id','caption')
    )
 
    # 下面的操作是让数据在网页上实时更新:每次刷新时,必先执行父类的初始化函数,再设定下拉列表框选项。
    def __init__(self, *args, **kwargs):
        super(UserInfoForm,self).__init__(*args, **kwargs)
        self.fields['user_type'].choices = models.UserType.objects.values_list('id','caption')
 
  #自定义清理数据字段操作:1、清理单个字段;2、清理多个字段;
    # def clean_username(self):
    #     #
    #     value = self.cleaned_data['username']
    #     if value == 'root':
    #         return value
    #     else:
    #         raise ValidationError('你不是我的...')
 
    # def clean(self):
    #     username = self.cleaned_data.get('username')
    #     email = self.cleaned_data.get('email')
    #     if models.User.objects.filter(username=username, email=email).count() == 1:
    #         raise ValidationError('用户名和邮箱联合唯一索引重复!!!')
    #     return self.cleaned_data
 
    #
    # def _post_clean(self):
    #     print 'aaa %s' %self.cleaned_data
    #     username = self.cleaned_data['username']
    #     email = self.cleaned_data['email']
    #     if models.User.objects.filter(username=username,email=email).count()==1:
    #         self.add_error("__all__", ValidationError('用户名和邮箱联合唯一索引重复!!!'))

  

  

3、前端文件index.html

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form action="/index/" method="POST" novalidate="novalidate">
        {% csrf_token %}
     #作为p标签展示,obj.as_table将内容渲染在tr中;obj.as_p,将内容渲染在p标签中;obj.as_ul将内容渲染在li标签中。
        {{ obj.as_p }}
        <input type="submit" value="提交">
    </form>
 
 
 <table>
       <th>
           <tr>用户名</tr>
           <tr>邮箱</tr>
           <tr>角色</tr>
       </th>
       {% for obj in new_obj %}
       <tr>
           <td>{{ obj.username }}</td>
           <td>{{ obj.email }}</td>
           <td>{{ obj.user_type.caption }}</td>
       </tr>
        {% endfor %}
   </table>
</body>
</html>

  

4、views.py文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
 
from django.shortcuts import render,HttpResponse
from app01 import models
from forms import UserInfoForm
# Create your views here.
 
 
def index(request):
    if request.method == 'GET':
        obj = UserInfoForm()
        new_obj = models.User.objects.all()
        return render(request,'index.html',{'obj':obj,'new_obj':new_obj})
    elif request.method == 'POST':
        obj = UserInfoForm(request.POST)
        if obj.is_valid():
            rt_dic = obj.cleaned_data
            username = rt_dic.get('username')
            email = rt_dic.get('email')
            user_type_id = rt_dic.get('user_type')
            ut = models.UserType.objects.filter(id=user_type_id).first()
            models.User.objects.create(username=username,email=email,user_type=ut)
        return render(request,'index.html',{'obj':obj})

  

5、效果

 POST提交数据:

 GET方式:

 

三、ModelForm模块

1、models.py文件

1
同上面的models.py文件

2、forms.py文件

 

1
2
3
4
5
6
class UserModelForm(forms.ModelForm):
    class Meta:
        #指定model的哪个表
        model = models.User
        #指定model的那些字段
        fields = "__all__"

  

3、前端文件index.html

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form action="/mf/" method="POST">
        {% csrf_token %}
        {{ obj.as_p }}
        <input type="submit" value="提交">
    </form>
 <table>
       <th>
           <tr>用户名</tr>
           <tr>邮箱</tr>
           <tr>角色</tr>
       </th>
       {% for obj in new_obj %}
       <tr>
           <td>{{ obj.username }}</td>
           <td>{{ obj.email }}</td>
           <td>{{ obj.user_type.caption }}</td>
       </tr>
        {% endfor %}
   </table>
</body>
</html>

  

 4、views.py文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
 
from django.shortcuts import render,HttpResponse
from app01 import models
from forms import UserInfoForm
from django import forms
 
# Create your views here.
 
def mf(request):
    if request.method == 'GET':
        obj = UserModelForm()
        new_obj = models.User.objects.all()
        return render(request,'index.html',{'obj':obj,'new_obj':new_obj})
    elif request.method == 'POST':
        obj = UserModelForm(request.POST)
        if obj.is_valid():
            obj.save()
        return render(request,'index.html',{'obj':obj})

  

5、效果

 

 

四、三种方式比较

共同点:

  • models.py,即数据库字段的定义都是一样。

不同点:

1、Model+原生Form

  • HTML里面的form表单字段需要用户自己写
  • 表单里面字段的格式错误需要用户自己判断,考虑的情况比较多【必选】
  • 保存方式为create()

2、Model+Form模块

  • 需要用户定义forms(表单字段以及字段验证方法【可选】)
  • HTML里面的form表单字段不需要用户写,直接使用obj.as_p就行
  • 保存方式为create()
  • 继承方式:UserForm -> Form -> BaseForm

3、纯ModelForm模块

  • 继承ModelForm,不需要自定义forms文件
  • 直接可以指定models的对象以及对象的字段
  • HTML里面的form表单字段不需要用户写,直接使用obj.as_p就行
  • 保存方式为save()
  • 继承方式:UserModelForm (ModelForm名称)-> ModelForm -> BaseModelForm【里面会有save方法】 -> BaseForm
  • is_valid()  ===>full_clean()=====>【self._clean_fields() 清洗单个字段     self._clean_form()清洗整个表单,调用clean()方法,自定义错误的钩子       self._post_clean()用户自定义错误的钩子】
posted @   skyflask  阅读(609)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 上周热点回顾(3.3-3.9)
· AI 智能体引爆开源社区「GitHub 热点速览」
点击右上角即可分享
微信分享提示