Django之ModelForm

什么是ModelForm

顾名思义,ModelForm就是数据模型和表单的结合体。单纯的Form表单只是对数据进行验证、在模板生成HTML。但这个ModelForm也包含了以上Form的功能,这是一个基于数据模型的一个组件,结合数据库使用的。

例一、利用ModelForm添加数据

有以下数据库

from django.db import models


# Create your models here.
class UserInfo(models.Model):
    username = models.CharField(max_length=32)
    password = models.CharField(max_length=32)

    def __str__(self):
        return self.username


class Host(models.Model):
    hostname = models.CharField(max_length=32, verbose_name='主机名')  # verbose_name用于在模板中生成label标签
    ip = models.GenericIPAddressField(protocol='ipv4')
    port = models.IntegerField()
    user = models.ForeignKey(to='UserInfo', on_delete=models.CASCADE, default=1)
    dp = models.ManyToManyField(to='Department')


class Department(models.Model):
    title = models.CharField(max_length=32)

    def __str__(self):
        return self.title

ModelForm的创建

from django.forms import widgets
from app01 import models
# 创建一个ModelForm类
class HostModelForm(ModelForm):
    class Meta:
        model = models.Host  # 定义了引用的数据模型
        fields = '__all__'  # 定义引用数据模型的哪些字段,也可以为列表,如['username','ip']
        # 定义标签名称,也可在数据模型中使用参数verbose_name定义
        labels = {
            'dp': '部门',
            'ip': 'IP',
            'port': '端口',
            'user': '用户名'
        }
        error_messages = {  # 定义错误信息
            'hostname': {'required': '用户名不能为空'},
            'ip': {'required': 'ip不能为空'},
            'port': {'required': '端口不能为空'},
            'dp': {'required': '必须要选部门'},
        }

表单中的渲染

{#        循环ModelForm,可获取每个field,相当于form.username、form.ip#}
{% for field in form %}
    

{{ field.label }}:{{ field }}{{ field.errors.0 }}

{% endfor %}

View视图函数

def add_host(request):
    if request.method == 'GET':
        form = forms.HostModelForm()  # 用于渲染网页
    else:
        form = forms.HostModelForm(data = request.POST)  # 校验数据
        if form.is_valid():
            form.save()  # 保存到数据库
            return redirect('/host/')
    return render(request, 'add_host.html', {'form': form})

利用ModelForm编辑数据

模板

{#        循环ModelForm,可获取每个field,相当于form.username、form.ip#}
{% for field in form %}
    

{{ field.label }}:{{ field }}{{ field.errors.0 }}

{% endfor %}

视图函数

def edit_host(request, nid):
    host_obj = models.Host.objects.filter(id=nid).first()
    if request.method == 'GET':
        form = forms.HostModelForm(instance=host_obj)  # 把对象传给ModelForm,以方便于网页渲染
    else:
        form = forms.HostModelForm(data=request.POST, instance=host_obj)  # 对instance实例用data更新数据
        if form.is_valid():
            form.save()
            return redirect('/host/')
    return render(request, 'edit_host.html', {'form': form})

要点总结

form = forms.HostModelForm()  # 用于渲染空的模板
form = forms.HostModelForm(instance = obj)  # 用于渲染一个带有obj数据的模板
form = forms.HostModelForm(data=request.POST)  # 准备校验的数据
form = forms.HostModelForm(data=request.POSt, instance = obj)  # 对对象obj更新数据
form.save()    # 保存数据
form.is_valid()  # 校验数据

内容补充

插件

这个插件的使用和Form差不多,但注意需要首先给widgets模块给个别名,因为这和参数名重复 示例如下:
from django.forms import fields
from django.forms import Form, ModelForm
from django.forms import widgets as mfwidgets  # 起一个别命
from app01 import models
class HostModelForm(ModelForm):
    class Meta:
        model = models.Host  # 定义了引用的数据模型
        fields = '__all__'  # 定义引用数据模型的哪些字段,也可以为列表,如['username','ip']
        # 定义标签名称,也可在数据模型中使用参数verbose_name定义
        labels = {
            'dp': '部门',
            'ip': 'IP',
            'port': '端口',
            'user': '用户名'
        }
        error_messages = {  # 定义错误类型
            'hostname': {'required': '用户名不能为空'},
            'ip': {'required': 'ip不能为空'},
            'port': {'required': '端口不能为空'},
            'dp': {'required': '必须要选部门'},
        }
        widgets = {  # 和form使用方法类似,这里演示了对hostname字段html的生成。
            'hostname': mfwidgets.Textarea(attrs={'class': 'c1'})
        }

钩子函数

和Form一样的

添加定制form字段

ModelForm是依赖于数据模型,而现在需要使用的是数据模型以外的字段,可在class Meta类上面定义,如下:
class HostModelForm(ModelForm):
    test = fields.CharField()  # 新增字段

    class Meta:
        model = models.Host  # 定义了引用的数据模型
        fields = '__all__'  # 定义引用数据模型的哪些字段,也可以为列表,如['username','ip']
        # 定义标签名称,也可在数据模型中使用参数verbose_name定义
        labels = {
            'dp': '部门',
            'ip': 'IP',
            'port': '端口',
            'user': '用户名'
        }
        error_messages = {  # 定义错误类型
            'hostname': {'required': '用户名不能为空'},
            'ip': {'required': 'ip不能为空'},
            'port': {'required': '端口不能为空'},
            'dp': {'required': '必须要选部门'},
        }
        widgets = {
            'hostname': mfwidgets.Textarea(attrs={'class': 'c1'})
        }

但如果定义的字段名与数据模型重复,会把数据模型的覆盖

posted on 2020-01-14 16:37  Treelight  阅读(148)  评论(0编辑  收藏  举报