欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

django之form组件

程序员文章站 2022-04-25 15:18:21
...

一、验证功能

html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form id="fm" action="/f1.html/" method="POST">
        <p><input type="text" name="user">{{ obj.errors.user.0 }}</p>
        <p><input type="text" name="pwd">{{ obj.errors.pwd.0 }}</p>
        <p><input type="text" name="age">{{ obj.errors.age.0 }}</p>
        <p><input type="text" name="email">{{ obj.errors.email.0 }}</p>
        <input type="submit" value="提交" />
    </form>
    <script src="/static/jquery-3.1.1.js"></script>

</body>
</html>

views

from django.shortcuts import render
from django.shortcuts import HttpResponse,redirect

from django import forms
from django.forms import fields

class F1Form(forms.Form):
    user = fields.CharField(
        max_length=20,
        min_length=2,
        required=True,
        error_messages={'required':'用户名不能为空','max_length':'不能超过20个字','min_length':'不能小于2个字'}

    )
    pwd = fields.CharField(required=True,min_length=8)
    age = fields.IntegerField(
        required=True,
        error_messages={
            'required':'不能为空',
            'invalid':'格式错误'
        }
                              )
    email = fields.EmailField(
        required=True,
        min_length=8,
        error_messages={
            'invalid':'格式错误'
        }
    )

def f1(request):
    if request.method == 'GET':
        obj = F1Form()
        return  render(request,'f1.html',{'obj':obj})
    else:
        obj = F1Form(request.POST)
        if obj.is_valid():
            print('验证成功',obj.cleaned_data)
            return HttpResponse('ok')
        else:
            print('验证失败',obj.errors)
            return render(request,'f1.html',{'obj':obj})

 

二、生成html

 

html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form id="fm" action="/f1.html/" method="POST">
        <p>{{ obj.user }}{{ obj.errors.user.0 }}</p>
        <p>{{ obj.pwd }}{{ obj.errors.pwd.0 }}</p>
        <p>{{ obj.age }}{{ obj.errors.age.0 }}</p>
        <p>{{ obj.email }}{{ obj.errors.email.0 }}</p>
        <input type="submit" value="提交" />
    </form>
    <script src="/static/jquery-3.1.1.js"></script>

</body>
</html>

views

from django.shortcuts import render
from django.shortcuts import HttpResponse,redirect

from django import forms
from django.forms import fields

class F1Form(forms.Form):
    user = fields.CharField(
        max_length=20,
        min_length=2,
        required=True,
        error_messages={'required':'用户名不能为空','max_length':'不能超过20个字','min_length':'不能小于2个字'}

    )
    pwd = fields.CharField(required=True,min_length=8)
    age = fields.IntegerField(
        required=True,
        error_messages={
            'required':'不能为空',
            'invalid':'格式错误'
        }
                              )
    email = fields.EmailField(
        required=True,
        min_length=8,
        error_messages={
            'invalid':'格式错误'
        }
    )

def f1(request):
    if request.method == 'GET':
        obj = F1Form()   #自动生成html
        return  render(request,'f1.html',{'obj':obj})
    else:
        obj = F1Form(request.POST)
        if obj.is_valid():
            print('验证成功',obj.cleaned_data)
            return HttpResponse('ok')
        else:
            print('验证失败',obj.errors)
            return render(request,'f1.html',{'obj':obj})

 

三、简单应用

models

from django.db import models


class UserInfo (models.Model):
    username = models.CharField (max_length=30)
    email = models.EmailField (max_length=50)

url

from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^users/', views.users),
    url(r'^add_user/', views.add_user),
    url(r'^edit_user-(\d+)/', views.edit_user),
]

 

users.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<a href="/add_user/">添加</a>
    <ul>
        {% for row in data %}
            <li>{{ row.id }}--{{ row.username }}--{{ row.email }}<a href="/edit_user_{{ row.id }}">编辑</a></li>
        {% endfor %}
    </ul>

</body>
</html>

 

add_user.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form action="/add_user/" method="post" novalidate>
    {% csrf_token %}
    <p>{{ obj.username }}{{ obj.errors.username.0 }}</p>
    <p>{{ obj.email }}{{ obj.errors.email.0 }}</p>
    <input type="submit" value="提交">
</form>
</body>
</html>

edit.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form action="/edit_user_{{ nid }}/" method="post" novalidate>
    {% csrf_token %}
    <p>{{ obj.username }}{{ obj.errors.username.0 }}</p>
    <p>{{ obj.email }}{{ obj.errors.email.0 }}</p>
    <input type="submit">
</form>

</body>
</html>

df

from django import forms
from django.forms import fields

class UserForm(forms.Form):
    username = fields.CharField()
    email = fields.EmailField()

 

views

 

from django.shortcuts import render,redirect
from app01 import models
from app01.df import UserForm

def users(request):
    data = models.UserInfo.objects.all()

    return render(request,'users.html',{'data':data})

def add_user(request):
    if request.method == 'GET':
        obj = UserForm()
        return render(request,'add_user.html',{'obj':obj})
    else:
        obj = UserForm(request.POST)
        if obj.is_valid():
            models.UserInfo.objects.create(**obj.cleaned_data)
            return redirect('/users/')
        else:
            return render(request,'add_user.html',{'obj':obj})

def edit_user(request,nid):
    if request.method =='GET':
        data = models.UserInfo.objects.filter(id=nid).first()
        obj =UserForm({'username':data.username,'email':data.email})
        return render(request,'edit_user.html',{'obj':obj,'nid':nid})
    else:
        obj =UserForm(request.POST)
        if obj.is_valid():
            models.UserInfo.objects.filter(id=nid).update(**obj.cleaned_data)
            return redirect('/users/')
        else:
            return render(request,'edit_user.html',{'obj':obj,'nid':nid})

四、组件字段

字段主要由正则匹配和插件构成

Field参数

required=True, widget=None, label=None, initial=None,help_text='', error_messages=None, show_hidden_initial=False,validators=(), localize=False, disabled=False, label_suffix=None

 

(1)CharField参数

具备Field参数

max_length=None, min_length=None, strip=True, empty_value=''
from django.shortcuts import render
from django import forms
from django.forms import fields,widgets
class TestForm(forms.Form):
    user = fields.CharField(
        required=True,   #是否必填
        max_length=12,    #最大长度
        min_length=3,     #最小长度
        error_messages={}, #错误提示
        # widgets = widgets.Select() ,#定制HTML插件
        label='用户名',
        initial='请输入用户名',   #初始化
        help_text='无用参数',
        show_hidden_initial=False,  #输入框不可修改
        disabled=True,
        label_suffix='-->'
    )
    age = fields.IntegerField()
    email = fields.EmailField()

def test(request):
    if request.method == 'GET':
        obj = TestForm()
        return render(request,'test.html',{'obj':obj})
    else:
        obj = TestForm (request.POST, request.FILES)
        obj.is_valid ()
        print (obj.cleaned_data)
        return render (request, 'test.html', {'obj': obj})

html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<table>
    {{ obj.as_table }}

</table>
<ul>
    {{ obj.as_ul }}
</ul>
{{ obj.as_p }}
</body>
</html>

显示

django之form组件

(2)IntegerField

具备Field参数

max_value=None, min_value=None

(3)其他

Field
    required=True,               是否允许为空
    widget=None,                 HTML插件
    label=None,                  用于生成Label标签或显示内容
    initial=None,                初始值
    help_text='',                帮助信息(在标签旁边显示)
    error_messages=None,         错误信息 {'required': '不能为空', 'invalid': '格式错误'}
    show_hidden_initial=False,   是否在当前插件后面再加一个隐藏的且具有默认值的插件(可用于检验两次输入是否一直)
    validators=[],               自定义验证规则
    localize=False,              是否支持本地化
    disabled=False,              是否可以编辑
    label_suffix=None            Label内容后缀
 
 
CharField(Field)
    max_length=None,             最大长度
    min_length=None,             最小长度
    strip=True                   是否移除用户输入空白
 
IntegerField(Field)
    max_value=None,              最大值
    min_value=None,              最小值
 
FloatField(IntegerField)
    ...
 
DecimalField(IntegerField)
    max_value=None,              最大值
    min_value=None,              最小值
    max_digits=None,             总长度
    decimal_places=None,         小数位长度
 
BaseTemporalField(Field)
    input_formats=None          时间格式化   
 
DateField(BaseTemporalField)    格式:2015-09-01
TimeField(BaseTemporalField)    格式:11:12
DateTimeField(BaseTemporalField)格式:2015-09-01 11:12
 
DurationField(Field)            时间间隔:%d %H:%M:%S.%f
    ...
 
RegexField(CharField)
    regex,                      自定制正则表达式
    max_length=None,            最大长度
    min_length=None,            最小长度
    error_message=None,         忽略,错误信息使用 error_messages={'invalid': '...'}
 
EmailField(CharField)      
    ...
 
FileField(Field)
    allow_empty_file=False     是否允许空文件
 
ImageField(FileField)      
    ...
    注:需要PIL模块,pip3 install Pillow
    以上两个字典使用时,需要注意两点:
        - form表单中 enctype="multipart/form-data"
        - view函数中 obj = MyForm(request.POST, request.FILES)
 
URLField(Field)
    ...
 
 
BooleanField(Field)  
    ...
 
NullBooleanField(BooleanField)
    ...
 
ChoiceField(Field)
    ...
    choices=(),                选项,如:choices = ((0,'上海'),(1,'北京'),)
    required=True,             是否必填
    widget=None,               插件,默认select插件
    label=None,                Label内容
    initial=None,              初始值
    help_text='',              帮助提示
 
 
ModelChoiceField(ChoiceField)
    ...                        django.forms.models.ModelChoiceField
    queryset,                  # 查询数据库中的数据
    empty_label="---------",   # 默认空显示内容
    to_field_name=None,        # HTML中value的值对应的字段
    limit_choices_to=None      # ModelForm中对queryset二次筛选
     
ModelMultipleChoiceField(ModelChoiceField)
    ...                        django.forms.models.ModelMultipleChoiceField
 
 
     
TypedChoiceField(ChoiceField)
    coerce = lambda val: val   对选中的值进行一次转换
    empty_value= ''            空值的默认值
 
MultipleChoiceField(ChoiceField)
    ...
 
TypedMultipleChoiceField(MultipleChoiceField)
    coerce = lambda val: val   对选中的每一个值进行一次转换
    empty_value= ''            空值的默认值
 
ComboField(Field)
    fields=()                  使用多个验证,如下:即验证最大长度20,又验证邮箱格式
                               fields.ComboField(fields=[fields.CharField(max_length=20), fields.EmailField(),])
 
MultiValueField(Field)
    PS: 抽象类,子类中可以实现聚合多个字典去匹配一个值,要配合MultiWidget使用
 
SplitDateTimeField(MultiValueField)
    input_date_formats=None,   格式列表:['%Y--%m--%d', '%m%d/%Y', '%m/%d/%y']
    input_time_formats=None    格式列表:['%H:%M:%S', '%H:%M:%S.%f', '%H:%M']
 
FilePathField(ChoiceField)     文件选项,目录下文件显示在页面中
    path,                      文件夹路径
    match=None,                正则匹配
    recursive=False,           递归下面的文件夹
    allow_files=True,          允许文件
    allow_folders=False,       允许文件夹
    required=True,
    widget=None,
    label=None,
    initial=None,
    help_text=''
 
GenericIPAddressField
    protocol='both',           both,ipv4,ipv6支持的IP格式
    unpack_ipv4=False          解析ipv4地址,如果是::ffff:192.0.2.1时候,可解析为192.0.2.1, PS:protocol必须为both才能启用
 
SlugField(CharField)           数字,字母,下划线,减号(连字符)
    ...
 
UUIDField(CharField)           uuid类型

 

比较常用:

        ChoiceField 
        MultipleChoiceField
        CharField
        IntegerField
        DecimalField
        DateField
        DateTimeField
        EmailField
        GenericIPAddressField
        FileField
        
        RegexField

五、字段插件

TextInput(Input)
NumberInput(TextInput)
EmailInput(TextInput)
URLInput(TextInput)
PasswordInput(TextInput)
HiddenInput(TextInput)
Textarea(Widget)
DateInput(DateTimeBaseInput)
DateTimeInput(DateTimeBaseInput)
TimeInput(DateTimeBaseInput)
CheckboxInput
Select
NullBooleanSelect
SelectMultiple
RadioSelect
CheckboxSelectMultiple
FileInput
ClearableFileInput
MultipleHiddenInput
SplitDateTimeWidget
SplitHiddenDateTimeWidget
SelectDateWidget

常用插件

# 单radio,值为字符串
# user = fields.CharField(
#     initial=2,
#     widget=widgets.RadioSelect(choices=((1,'上海'),(2,'北京'),))
# )
 
# 单radio,值为字符串
# user = fields.ChoiceField(
#     choices=((1, '上海'), (2, '北京'),),
#     initial=2,
#     widget=widgets.RadioSelect
# )
 
# 单select,值为字符串
# user = fields.CharField(
#     initial=2,
#     widget=widgets.Select(choices=((1,'上海'),(2,'北京'),))
# )
 
# 单select,值为字符串
# user = fields.ChoiceField(
#     choices=((1, '上海'), (2, '北京'),),
#     initial=2,
#     widget=widgets.Select
# )
 
# 多选select,值为列表
# user = fields.MultipleChoiceField(
#     choices=((1,'上海'),(2,'北京'),),
#     initial=[1,],
#     widget=widgets.SelectMultiple
# )
 
 
# 单checkbox
# user = fields.CharField(
#     widget=widgets.CheckboxInput()
# )
 
 
# 多选checkbox,值为列表
# user = fields.MultipleChoiceField(
#     initial=[2, ],
#     choices=((1, '上海'), (2, '北京'),),
#     widget=widgets.CheckboxSelectMultiple
# )

 

 choices选项从数据库中自动更新

方式一

from django.forms import Form
from django.forms import widgets
from django.forms import fields


class MyForm(Form):

    user = fields.ChoiceField(
        # choices=((1, '上海'), (2, '北京'),),
        initial=2,
        widget=widgets.Select
    )

    def __init__(self, *args, **kwargs):
        # 拷贝所有的静态字段,复制给self.fields
        super(MyForm,self).__init__(*args, **kwargs)
        # self.fields['user'].widget.choices = ((1, '上海'), (2, '北京'),)
        # 或
        self.fields['user'].widget.choices = models.Classes.objects.all().value_list('id','caption')

 

方式二

rom django import forms
from django.forms import fields
from django.forms import widgets
from django.forms import models as form_model
from django.core.exceptions import ValidationError
from django.core.validators import RegexValidator
 
class FInfo(forms.Form):
    authors = form_model.ModelMultipleChoiceField(queryset=models.NNewType.objects.all())
    # authors = form_model.ModelChoiceField(queryset=models.NNewType.objects.all())

 

ajax提交后只能接受后端字符串,不会接受后端的跳转,也就只能在前端设置跳转。所以ajax提交错误信息要自己展示,跳转要自己跳转。

views

def ajax(request):
    if request.method == 'GET':
        obj = AjaxForm()
        return render(request,'ajax.html',{'obj':obj})
    else:
        ret = {'status':'no','message':None}
        import json
        obj = AjaxForm(request.POST)
        if obj.is_valid():
            

            ret['status'] = 'yes'
            return HttpResponse(json.dumps(ret))
        else:
            # print(type(obj.errors))
            # print(obj.errors)
            from django.forms.utils import ErrorDict
            # print(obj.errors.as_ul())
            # print(obj.errors.as_json())
            # print(obj.errors.as_data())



            ret['message'] = obj.errors
            # 错误信息显示在页面上
            return HttpResponse(json.dumps(ret))

html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form id="fm" method="POST" action="/ajax/">
        {% csrf_token %}
        {{ obj.as_p }}
        <input type="button" value="Ajax提交" id="btn" />
    </form>
    <script src="/static/jquery-3.1.1.js"></script>
    <script>
        $(function () {
            $('#btn').click(function () {
                $.ajax({
                    url: '/ajax/',
                    type: 'POST',
                    data: $('#fm').serialize(),
                    dataType: 'JSON',
                    success:function (arg) {

                        // arg: 状态,错误信息
                        if (arg.status == 'yes'){
                            window.location.href = "http://www.baidu.com"
                        }
                        console.log(arg);
                    }
                })


            })


        })
    </script>
</body>
</html>

六、简单扩展

1,插件扩展

自定制验证规则

利用Form组件自带的正则扩展:
            a. 方式一
                from django.forms import Form
                from django.forms import widgets
                from django.forms import fields
                from django.core.validators import RegexValidator
                 
                class MyForm(Form):
                        user = fields.CharField(
                        error_messages={'invalid': '...'},
                        validators=[RegexValidator(r'^[0-9]+$', '请输入数字'), RegexValidator(r'^159[0-9]+$', '数字必须以159开头')],
                    )
            b. 方式二
                from django.forms import Form
                from django.forms import widgets
                from django.forms import fields
                from django.core.validators import RegexValidator
                 
                class MyForm(Form):
                user = fields.RegexField(r'^[0-9]+$',error_messages={'invalid': '...'})

 2.基于源码流程

验证数据库中是否存在同名用户

 
        a. 单字段
            from django.core.exceptions import NON_FIELD_ERRORS, ValidationError
            class AjaxForm(forms.Form):
                username = fields.CharField()
                user_id = fields.IntegerField(
                    widget=widgets.Select(choices=[(0,'alex'),(1,'BOB'),(2,'ALICE'),])
                )
            # 自定义方法 clean_字段名
            # 必须返回值self.cleaned_data['username']
            # 如果出错:raise ValidationError('用户名已存在')
            def clean_username(self):
                v = self.cleaned_data['username']
                if models.UserInfo.objects.filter(username=v).count():
                    # 整体错了
                    # 自己详细错误信息
                    raise ValidationError('用户名已存在')
                return v
            def clean_user_id(self):
                return self.cleaned_data['user_id']

        b. 整体错误验证
            class AjaxForm(forms.Form):
                username = fields.CharField()
                user_id = fields.IntegerField(
                    widget=widgets.Select(choices=[(0,'alex'),(1,'BOB'),(2,'ALICE'),])
                )
                # 自定义方法 clean_字段名
                # 必须返回值self.cleaned_data['username']
                # 如果出错:raise ValidationError('用户名已存在')
                def clean_username(self):
                    v = self.cleaned_data['username']
                    if models.UserInfo.objects.filter(username=v).count():
                        # 整体错了
                        # 自己详细错误信息
                        raise ValidationError('用户名已存在')
                    return v
                def clean_user_id(self):
                    return self.cleaned_data['user_id']

                def clean(self):
                    value_dict = self.cleaned_data
                    v1 = value_dict.get('username')
                    v2 = value_dict.get('user_id')
                    if v1 == 'root' and v2==1:
                        raise ValidationError('整体错误信息')
                    return self.cleaned_data
                    
                    
        PS: _post_clean
                

 

七、序列化

from django.shortcuts import render
from django.shortcuts import HttpResponse
from app01 import models
import json
def xuliehua(request):

    return render(request,'xuliehua.html')

"""
def get_data(request):
    user_list = models.UserInfo.objects.all()
    return render(request,'get_data.html',{'user_list':user_list})
"""
def get_data(request):
    from django.core import serializers

    ret = {'status':True,'data':None}
    try:
        # user_list = models.UserInfo.objects.all()
        # QuerySet【obj,obj,obj】
        # ret['data'] = serializers.serialize("json",user_list)
        # // var
        # v = JSON.parse(arg.data);
        # // console.log(v);

        # user_list = models.UserInfo.objects.all().values('id','username')
        # ret['data'] = list(user_list)
        # console.log(arg.data);

        # user_list = models.UserInfo.objects.all().values_list('id', 'username')
        # ret['data'] = list(user_list)
        # console.log(arg.data);
        pass
    except Exception as e:
        ret['status'] = False
    result = json.dumps(ret)
    return HttpResponse(result)

 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>用户列表</h1>
    <table id="tb">

    </table>
    <script src="/static/jquery-3.1.1.js"></script>
    <script>
        $(function () {
            initData();
        });
        function initData() {
            $.ajax({
                url :'/get_data/',
                type:'GET',
                dataType:'JSON',
                success:function (arg) {
                    //$('#tb').append(arg);
                    if(arg.status){
                        console.log(arg.data);
                        //var v = JSON.parse(arg.data);
                        //console.log(v);
                    }
                }
            })
        }
    </script>
</body>
</html>