Django之Form组件

此文是简单翻译http://www.cnblogs.com/wupeiqi/articles/6144178.html 如有不懂看这个网址把,不过加了代码应该能看懂

Django的Form主要具有一下几大功能:

  • 生成HTML标签
  • 验证用户数据(显示错误信息)
  • HTML Form提交保留上次提交数据
  • 初始化页面显示内容

区别:

  - form表单(验证;保留上次内容)
        - 
    - Ajax(验证;无需上次内容)
        - 返回HttpResponse
        - 前端:跳转或错误信息

 

在form表单里加   novalidate   浏览器报错取消

 

cleaned_data 就是读取表单返回的值,返回类型为字典dict型
email=cleaned_data['email']  读取name为 ‘email’的表单提交值,并赋予 email变量

 

一。熟悉Form类

1.创建Form类

from django.forms import Form
from django.forms import widgets
from django.forms import fields
 
class MyForm(Form):
    user = fields.CharField(
        widget=widgets.TextInput(attrs={'id': 'i1', 'class': 'c1'})
    )
 
    gender = fields.ChoiceField(
        choices=((1, '男'), (2, '女'),),
        initial=2,
        widget=widgets.RadioSelect
    )
 
    city = fields.CharField(
        initial=2,
        widget=widgets.Select(choices=((1,'上海'),(2,'北京'),))
    )
 
    pwd = fields.CharField(
        widget=widgets.PasswordInput(attrs={'class': 'c1'}, render_value=True)
    )

2、View函数处理

from django.shortcuts import render, redirect
from .forms import MyForm
 
 
def index(request):
    if request.method == "GET":
        obj = MyForm()          #生成html
        return render(request, 'index.html', {'form': obj})
    elif request.method == "POST":
        obj = MyForm(request.POST, request.FILES)
        if obj.is_valid():       #判断是否验证成功
            values = obj.clean()
            print(values)
        else:
            errors = obj.errors
            print(errors)
        return render(request, 'index.html', {'form': obj})
    else:
        return redirect('http://www.google.com')

 

3.生成HTML

<form action="/" method="POST" enctype="multipart/form-data">
    <p>{{ form.user }} {{ form.user.errors }}</p>
    <p>{{ form.gender }} {{ form.gender.errors }}</p>
    <p>{{ form.city }} {{ form.city.errors }}</p>
    <p>{{ form.pwd }} {{ form.pwd.errors }}</p>
    <input type="submit"/>
</form>

form.gender.errors显示的是错误信息,有很多错误信息的话form.gender.errors.0  加个.0显示第一个

 

二。Form类

创建Form类时,主要涉及到 【字段】 和 【插件】,字段用于对用户请求数据的验证,插件用于自动生成HTML;

1、Django内置字段如下(捡几个重要的)

a.

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内容后缀

 

b.

CharField(Field)         

    max_length=None,             最大长度

    min_length=None,             最小长度

    strip=True                   是否移除用户输入空白

 

c.

IntegerField(Field)          FloatField(IntegerField)    :这是浮点型的字段,继承了IntegerField

    max_value=None,              最大值

    min_value=None,              最小值

 

d.

RegexField(CharField)

    regex,                      自定制正则表达式

    max_length=None,            最大长度

    min_length=None,            最小长度

    error_message=None,         忽略,错误信息使用 error_messages={'invalid': '...'}

 

e.

FileField(Field)           

    allow_empty_file=False     是否允许空文件

ImageField(FileField)      

    ...

    注:需要PIL模块,pip3 install Pillow

    以上两个字典使用时,需要注意两点:

        - form表单中 enctype="multipart/form-data"

        - view函数中 obj = MyForm(request.POST, request.FILES)

 

f。

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

 

①。在app里创建应该forms.py文件,里面创建form类

from django import forms as dforms
from django.forms import fields


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

②。在views下写入相对应的函数

from django.shortcuts import render
from django.shortcuts import redirect
from app01 import models
def users(request):
    user_list = models.UserInfo.objects.all()
    return render(request,'users.html',{'user_list':user_list})
from app01.forms import UserForm

# url(r'^add_user/', views.add_user),
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})
# url(r'^edit_user-(\d+)/', views.edit_user),
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})

?。前端页面

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_user.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" value="提交" />
    </form>
</body>
</html>

2.常用选择插件

# 单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

# )

 

举例:

传文件、图片的例子:

创建form类

from django.shortcuts import render
from django.shortcuts import redirect
from django.shortcuts import HttpResponse
from django import forms
from django.forms import fields
from django.forms import widgets
class TestForm(forms.Form):
    user = fields.CharField(
        required=True, # 是否必填
        max_length=12, # 最大长度
        min_length=3,  # 最小长度
        error_messages={}, # 错误提示
        widget = widgets.TextInput(attrs={'class':'c1'}), # 定制HTML插件
        label='用户名',
        initial='请输入用户',
        help_text='asdfasdf',
        show_hidden_initial=False,
        # validators=[]
        disabled=True,
        label_suffix='->'
    )
    age = fields.IntegerField(
        label='年龄',
        max_value= 12,
        min_value=5,
        error_messages={
            'max_value':'太大了'
        }
    )

    email = fields.EmailField(
        label='邮箱'
    )

    img = fields.FileField()

    city = fields.TypedChoiceField(
        coerce=lambda x: int(x),
        choices=[(1,'上海',),(2,'北京'),(3,'沙河'),],
        initial=2
    )
    hobby = fields.MultipleChoiceField(
        choices=[(1,'刚娘'),(2,'铁娘'),(3,'钢弹')],
        initial=[1,2]
    )

传文件时在form表单后面加      

enctype="multipart/form-data"  
表示后端能接收到文件类型的 数据
def test(request):
    if request.method == 'GET':
        #obj = TestForm({'city':3})
        obj = TestForm()
        txt = "<input type='text' />"
        from django.utils.safestring import mark_safe
        txt = mark_safe(txt)#这样设置后就不要在前端页面加safe了
        return render(request,'test.html',{'obj':obj,'txt':txt})
    else:
        obj = TestForm(request.POST,request.FILES)   #多添加了一个文件参数
        obj.is_valid()
        print(obj.cleaned_data)
        return render(request, 'test.html', {'obj': obj})
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    {{ txt }}
{#    enctype="multipart/form-data"  表示后端能接收到文件类型的 数据#}
    <form method="POST" action="/test/" novalidate enctype="multipart/form-data">

        {% csrf_token %}
        <p>{{ obj.user.label }}{{ obj.user }}</p>
        <p>{{ obj.age.label }}{{ obj.age }}{{ obj.errors.age.0 }}</p>
        <p>{{ obj.email.label }}{{ obj.email }}</p>
        <p>{{ obj.img.label }}{{ obj.img }}</p>
        <p>{{ obj.city.label }}{{ obj.city }}</p>
        <p>{{ obj.hobby.label }}{{ obj.hobby }}</p>
        <p>{{ obj.xdb.label }}{{ obj.xdb }}</p>
        <input  type="submit" value="提交"/>
    </form>
</body>
</html>

 

修改数据不用重启服务直接显示

from app01 import models
from django.forms.models import ModelChoiceField
#像price user_id都是静态属性,程序一运行就在内存中不变了
#所以要加  def  __init__    拷贝所有的静态字段,复制给self.fields
class LoveForm(forms.Form):
    price = fields.IntegerField()
    user_id = fields.IntegerField(
        # widget=widgets.Select(choices=[(0,'alex'),(1,'刘皓宸'),(2,'杨建'),])
        widget=widgets.Select()
    )

    user_id2 = ModelChoiceField(
        queryset=models.UserInfo.objects.all(),
        to_field_name='id'
    )

    def __init__(self,*args,**kwargs):
        # 拷贝所有的静态字段,复制给self.fields
        super(LoveForm,self).__init__(*args,**kwargs)
        self.fields['user_id'].widget.choices = models.UserInfo.objects.values_list('id', 'username')


def love(request):
    obj = LoveForm()
    return render(request,'love.html',{'obj':obj})

 

利用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': '...'})

 

自定制匹配规则(ajax):

# 自定义方法 clean_字段名
# 必须返回值self.cleaned_data['username']
# 如果出错:raise ValidationError('用户名已存在')
as_p表示把form表单在前端页面渲染成p标签的形式展示,此外还有as_ul,as_table等。
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,'刘皓宸'),(2,'杨建'),])
    )
    # 自定义方法 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


def ajax(request):
    if request.method == 'GET':
        obj = AjaxForm()
        return render(request,'ajax.html',{'obj':obj})
    else:
        ret = {'status':'杨建','message':None}
        import json
        obj = AjaxForm(request.POST)
        if obj.is_valid():
            # 跳转到百度
            # return redirect('http://www.baidu.com')
            # if ....
            #     obj.errors['username'] = ['用户名已经存在',]
            # if ....
            #     obj.errors['email'] = ['用户名已经存在',]

            ret['status'] = '钱'
            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())
            """
            {
               __all__: [],
               username:[]
            }
            """
            ret['message'] = obj.errors
            # 错误信息显示在页面上
            return HttpResponse(json.dumps(ret))

 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form id="fm" method="POST" action="/ajax/">
        {% csrf_token %}
{#        as_p表示把form表单在前端页面渲染成p标签的形式展示,此外还有as_ul,as_table等。#}
        {{ 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 == '钱'){
                            window.location.href = "http://www.baidu.com"
                        }
                        console.log(arg);
                    }
                })


            })


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

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值