天天看點

第24天,Django之ModelForm

一. 建立一個ModelForm

1.1 使用之前需要導入對應app中的models和Django送出的ModelForm類

from django.forms import ModelForm
from app01.models import Host
from django.forms import widgets           #插件,接下來會用到
from django.core.exceptions import ValidationError         
           

1.2 建立一個類,并繼承ModelForm

class HostModelForm(ModelForm):             #建立1個類,繼承ModelForm
    class Meta:                             #在内部定義一個Meta類,注意這個類名是固定不變的
        model = Host                        #對應models.py中哪個類(哪個表)
        fields = '__all__'                  #表示使用models.Host類中所有字段
        # fields = ('hostname','ip','port','dep')    #也可以這樣選擇指定字段
           

ModelForm常用的class Meta配置

class Meta:
        model = models.UserInfo            #結尾不用加逗号
        fields = '__all__'
        # fields =  ['username','email']
        # exclude = ['username']            # 除了 XX字段,其他都使用
        labels = {                          # label 名稱
            'username': '使用者名',
            'email': '郵箱',
        }
        help_texts = {                     # 幫助資訊
            'username': '...'
        }
        widgets = {
            'username': Fwidgets.Textarea(attrs={'class': 'c1'})
        }
        error_messages = {                       # 自定義錯誤
            '__all__':{

            },
            'email': {
                'required': '郵箱不能為空',
                'invalid': '郵箱格式錯誤..',
            }
        }
        field_classes = {                         #字段類型,可以強制修改成其他類型
            # 'email': Ffields.URLField
        }

        # localized_fields=('ctime',)
           

二. ModelForm生成Html和資料驗證

2.1 生成空表單

forms = HostModelForm()     # 生成空的表單
           

2.2 在表單中顯示初始資料

hostobj =models.Host.objects.get(id=1)
forms = HostModelForm(instance = hostobj)          # instance  對應模型執行個體 
           

2.3 驗證表單資料并儲存

forms = HostModelForm(request.POST)
if forms.is_valid():              # 驗證成功則儲存modelsform
    forms.save()                  # 這一步會直接将資料儲存至資料庫
           
注意:此時,forms.save()不僅儲存目前對象執行個體,還儲存執行個體對應跨表關系(外鍵、多對多等)

三. 前端頁面展示form表

在模版中展示指定字段

<form method="post" novalidate>
    {% csrf_token %}
    <p>{{ forms.hostname.label }}:&nbsp;{{ forms.hostname }}{{ forms.hostname.errors.0 }}</p>
    <p>{{ forms.ip.label }}:&nbsp;{{ forms.ip }}{{ forms.ip.errors.0 }}</p>
    <p>{{ forms.port.label }}:&nbsp;{{ forms.port }}{{ forms.port.errors.0 }}</p>
    <input type="submit" value="送出">
</form>
           

如果嫌上面這種方法麻煩,還可以在模版中循環forms執行個體,以列出每個字段

<form method="post" novalidate>
    {% csrf_token %}
    {% for form in forms %}
       <p>{{ form.label }}:&nbsp;{{ form }}{{ form.errors.0 }}</p>
    {% endfor %}
    <input type="submit" value="送出">
</form>
           

四. 示例

4.1 在app中建立一個forms.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author : Cai Guangyin

from django.forms import ModelForm
from app01.models import Host
from django.forms import widgets
from django.core.exceptions import ValidationError


class HostModelForm(ModelForm):             #建立1個類,繼承ModelForm
    class Meta:
        model = Host                        #對應models.py中哪個類(哪個表)
        fields = '__all__'                  #表示使用models.Host類中所有字段
        # fields = ('hostname','ip','port','dep')    #也可以這樣選擇指定字段
        error_messages = {                  #自定義錯誤提示資訊
            'hostname':{
                'required':'使用者名不能為空'
            },
            'ip':{
                'required':'IP不能為空',
                'invalid':'IP位址格式錯誤'
            },
            'port':{
                'required':'端口不能為空'
            },
            'dep': {
                'required': '部門不能為空'
            },
            'userinfo': {
                'required': '所屬使用者不能為空'
            },
        }
        labels = {                      #自定義label标簽顯示的内容
            'hostname':'主機名',
            'ip':'IP',
            'port':'端口',
            'dep':'部門',
            'userinfo':'所屬使用者'
        }
        widgets = {       # 自定義插件,注意必須加s,因為是複數,寫widget不起作用
            'hostname': widgets.TextInput(attrs={'class':'form-control'}),
            'ip': widgets.TextInput(attrs={'class':'form-control'}),
            'port': widgets.TextInput(attrs={'class':'form-control'}),
            'dep': widgets.Select(attrs={'class':'form-control'}),
            'userinfo': widgets.SelectMultiple(attrs={'class':'form-control'}),
        }

    def clean_port(self):      #也可以自定義鈎子函數對字段進行驗證
        value = self.cleaned_data['port']
        if int(value) > 65535:
            raise ValidationError('端口号不能大于65535')
        return value
           

4.2 views.py

from django.shortcuts import render
from .models import *
from .forms import HostModelForm
# Create your views here.

def index(request):
    forms = HostModelForm()            #建立空表單
    if request.method == 'POST':
        forms = HostModelForm(request.POST)     #送出資料
        if forms.is_valid():                    #驗證資料 
            forms.save()
    return render(request,'index.html',locals())

def edit_host(request):
    host_obj = Host.objects.filter(pk=1).first()
    forms = HostModelForm(instance=host_obj)   #編輯時顯示預設資料
    if request.method == 'POST':
        # host_obj = Host.objects.filter(pk=1).first()
        # forms = HostModelForm(request.POST)    #向modelform中傳遞資料
        forms = HostModelForm(data=request.POST,instance=host_obj)  #編輯儲存時,需要将data和instance都傳入
        if forms.is_valid():
            forms.save()
    return render(request,'edithost.html',locals())
           
注意:在修改表單(表單中有初始值),送出驗證時,需要傳入data和instance兩個參數,如:

forms = HostModelForm(data=request.POST,instance=host_obj)

4.3 模版檔案

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<form method="post" novalidate>
    {% csrf_token %}
    {% for form in forms %}
       <p>{{ form.label }}:&nbsp;{{ form }}{{ form.errors.0 }}</p>
    {% endfor %}
    <input type="submit" value="送出">
</form>

</body>
</html>