【ジャンゴ】フォームアセンブリ--2019-08-16十一時56分26秒

オリジナル:http://blog.gqylpy.com/gqy/269

「@
***

フォームコンポーネント入門

HTMLページ内のフォームを使用してバックエンドにフォームデータを提出する際、ユーザー入力を取得するためにラベルを書き、フォームのラップでそれらをラベル付けします。

同時に、我々はすべて、このようなユーザー入力かどうかを確認するなど、ユーザーの入力の検証のシーン、多くの中で行う必要があり、入力長と形式が正しくありません。ユーザ入力がエラーを有する場合、ページ上の位置に対応する適切なエラーメッセージを必要とします。

上記の機能の実現にDjangoのフォーム部品。

次のように、フォームコンポーネントの主な機能を要約します。

  1. HTMLタグは使用可能なページを生成しました
  2. ユーザーから提出されたデータを確認するには
  3. 予約内容の入力をアップロード
    ***

    簡単な登録の例

    フォームファイル:
from django import forms

# 按照Django form组件的要求自己写一个类
# 且必须继承forms.Form
class RegForm(forms.Form):
    user = forms.CharField(label="名称")
    pwd = forms.CharField(label="密码", min_length=6)

ビューのファイル:

from django.shortcuts import render, HttpResponse
from blog01 import forms  # 导入上面的form文件

def register(request):
    form_obj = forms.RegForm()
    if request.method == 'POST':
        form_obj = forms.RegForm(request.POST)
        if form_obj.is_valid():
            # 只有执行了is_valid之后,才可执行cleaned_data,否则会报错
            # cleaned_data的数据是经过校验的
            print(form_obj.cleaned_data)
            return HttpResponse("注册成功!")
    return render(request, 'register.html', {'form': form_obj})

HTMLファイル:

<body>
{# novalidate:阻止验证(form组件会自动验证)#}
<form action="" method="post" novalidate>
{% csrf_token %}
    {# {{ form.as_p }}  以p标签的形式自动生成 #}
    {# 下面为简单的自定义形式 #}
    <p>
        {{ form.user.label }}
        {{ form.user }}
        {# 错误提示信息 #}
        {# {{ form.errors }}  生成form表单的所有错误信息(全局错误信息)#}
        {# <span style="color: red">{{ form.user.errors }}</span>  指定字段的所有错误信息 #}
        <span style="color: red">{{ form.user.errors.0 }}</span> {# 指定字段的所有错误信息的第一个 #}
    </p>
    <p>
        {{ form.pwd.label }}
        {{ form.pwd }}
        <span style="color: red">{{ form.pwd.errors.0 }}</span>
    </p>
    <button>注册</button>
</form>
</body>


プラグインとの共通のフィールド

from django import forms


class RegForm(forms.Form):
    user = forms.CharField(
        label="名称",  # 用于生成label标签或显示内容
        # required=False,  # 为False时,允许为空
        min_length=2,  # 最小长度
        max_length=6,  # 最大长度
        initial='zyk01',  # 初始值
        error_messages={
            'required': "用户名不能为空",
            'invalid': "用户名格式错误",
            'min_length': "用户名最短2位",
        }  # 自定义错误提示
    )

    pwd = forms.CharField(
        label="密码",
        min_length=6,
        error_messages={
            'required': "密码不能为空",
            'invalid': "密码格式错误",
            'min_length': "密码最短6位",
        },
        widget=forms.widgets.PasswordInput(),  # 指定input的type类型为password
    )

    # ===================================================
    #    
    # ===================================================

    """checkbox标签(单选)"""
    keep = forms.fields.CharField(
        label="记住密码",
        initial='checked',  # 默认选中
        widget=forms.widgets.CheckboxInput(),
    )

    """checkbox标签(多选)"""
    hobby01 = forms.fields.MultipleChoiceField(
        label="爱好01",
        choices=((1, "篮球"), (2, "足球"), (3, "乒乓球"),),
        initial=[1, 2],  # 默认选中1, 2
        widget=forms.widgets.CheckboxSelectMultiple(),
    )

    """radioSelect(等价于<input type="radio">)"""
    gender = forms.fields.ChoiceField(
        label="性别",
        choices=((1, "男"), (2, "女"), (3, "阴阳人"),),
        initial=1,  # 默认选中1
        widget=forms.widgets.RadioSelect(),
    )

    """Select标签"""
    hobby02 = forms.fields.ChoiceField(
        choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
        label="爱好02",
        initial=3,  # # 默认选中3
        # widget=forms.widgets.Select(),  # 实现单选Select
        widget=forms.widgets.SelectMultiple(),  # 实现多选Select
    )

フォームのコンポーネントはすべて、組み込みの分野

Field
    required=True,               是否允许为空
    widget=None,                 HTML插件
    label=None,                  用于生成Label标签或显示内容
    initial=None,                初始值
    help_text='',                帮助信息(在标签旁边显示)
    error_messages=None,         错误信息 {'required': '不能为空', 'invalid': '格式错误'}
    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类型

データベースからデータを取得します。

selectタグを使用するときは、オプションの選択に注意を払う必要があり、データベースから取得することができ、それが静的フィールドでアップデートを実装することができません取得し、値が== ==、この目的を達成するためにカスタムメソッドを構築する必要があります。

from django import forms
from blog01 import models

class RegForm(forms.Form):
    hobby03 = forms.fields.ChoiceField(
        label="爱好03",
        # choices=models.Hobby.objects.values_list('id', 'name'),
        widget=forms.widgets.CheckboxSelectMultiple(),
    )

    def __init__(self, *args, **kwargs):
        super(RegForm, self).__init__(*args, **kwargs)
        # self.fields['hobby03'].choices = ((1, 'Python'), (2, 'Django'),)
        self.fields['hobby03'].choices =  models.Hobby.objects.values_list('id','name')


例を確認します


チェックの電話番号が正当なものです

ビューのファイル:

from django.shortcuts import render, HttpResponse
from blog01 import forms  # 导入form文件

def register(request):
    form_obj = forms.RegForm()
    if request.method == 'POST':
        form_obj = forms.RegForm(request.POST)
        if form_obj.is_valid():
            # 只有执行了is_valid之后,才可执行cleaned_data,否则会报错
            # cleaned_data的数据是经过校验的
            print(form_obj.cleaned_data)
            return HttpResponse("注册成功!")
    return render(request, 'register.html', {'form': form_obj})

HTMLファイル:

<body>
{# novalidate:阻止验证(form组件会自动验证)#}
<form action="" method="post" novalidate>
    {% csrf_token %}
    <p>
        {{ form.phone.label }}
        {{ form.phone }}
        <span style="color: red">{{ form.phone.errors.0 }}</span>
    </p>
    <button>注册</button>
</form>
</body>

モード(基本)

フォームファイル:

from django import forms
from django.core.validators import RegexValidator

class RegForm(forms.Form):
    phone = forms.fields.CharField(
        label="手机号",
        validators=[
            RegexValidator(r'^1[3-9]\d{9}$', "号码不合法")
            # RegexValidator(r"正则表达式", "错误提示信息")
        ],
    )

第二の方法(カスタム検証ルール)

フォームファイル:

import re
from django.forms import Form
from django.forms import widgets
from django.forms import fields
from django.core.exceptions import ValidationError


# 自定义验证规则
def mobile_validate(value):
    mobile_re = re.compile(r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$')
    if not mobile_re.match(value):
        raise ValidationError("手机号格式错误")


class RegForm(Form):
    phone = fields.CharField(
        label="手机号",
        # 使用自定义验证规则
        # validators=[校验器函数1, 校验器函数2]
        validators=[mobile_validate, ],
        error_messages={'required': "手机号不能为空", },
        widget=widgets.TextInput(
            attrs={'class': 'form-control', 'placeholder': u"手机号码"},
        )
    )

三つの方法(フックを使用して)

フォームファイル:

import re
from django.forms import Form
from django.forms import widgets
from django.core.exceptions import ValidationError


class RegForm(Form):
    phone = forms.fields.CharField(
        label="手机号",
        error_messages={'required': "手机号不能为空", },
        widget=widgets.TextInput(
            attrs={'class': 'form-control', 'placeholder': u"手机号码"},
        )
    )

    def clean_phone(self):
        value = self.cleaned_data.get('phone')
        mobile_re = re.compile(r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$')
        if  mobile_re.match(value):
            return value
        raise ValidationError("手机号不合法")

パスワードの一貫性を確認してください

ビューファイル同上⬆️

フォームファイル:

from django.forms import Form
from django.core.validators import RegexValidator


class RegForm(Form):
    pwd = forms.CharField(
        label="密码",
        min_length=6,
        widget=widgets.PasswordInput(),
    )
    re_pwd = forms.CharField(
        label="确认密码",
        min_length=6,
        widget=widgets.PasswordInput(),
    )

    def clean_re_pwd(self):
        pwd = self.cleaned_data.get('pwd')
        re_pwd = self.cleaned_data.get('re_pwd')
        if pwd == re_pwd:
            return re_pwd
        raise ValidationError("密码不一致")

HTMLファイル:

<body>
{# novalidate:阻止验证(form组件会自动验证)#}
<form action="" method="post" novalidate>
    {% csrf_token %}
    {# {{ form.as_p }}  以p标签的形式自动生成 #}
    <p>
        {{ form.pwd.label }}
        {{ form.pwd }}
        <span style="color: red">{{ form.pwd.errors.0 }}</span>
    </p>
    <p>
        {{ form.re_pwd.label }}
        {{ form.re_pwd }}
        <span style="color: red">{{ form.re_pwd.errors.0 }}</span>
    </p>
    <button>注册</button>
</form>
</body>


フック


ローカルフック

from django.forms import Form


class RegForm(Form):
    test01 = forms.CharField()

    test02 = forms.CharField()

    test03 = forms.CharField()

    # 局部钩子
    def clean_test02(self):
        test01 = self.cleaned_data.get('test01')
        test02 = self.cleaned_data.get('test02')
        test03 = self.cleaned_data.get('test03')
        print(test01, test02, test03)  # test03的值定会为None
        return test02

    """
    这里定义的是test02的钩子
    ! 定义哪个字段的钩子,就得返回哪个字段的值
    此时的钩子只能获取test01与test02的值,而test03的值为None
    因为test03字段在test02字段的下面,所以test02的钩子无法获取test03的值(更多可看源码)
    """

グローバルフック

from django.forms import Form


class RegForm(Form):
    test01 = forms.CharField()

    test02 = forms.CharField()

    test03 = forms.CharField()

    # 全局钩子
    def clean(self):
        test01 = self.cleaned_data.get('test01')
        test02 = self.cleaned_data.get('test02')
        test03 = self.cleaned_data.get('test03')
        print(test01, test02, test03)
        return self.cleaned_data

    """
    这里定义的是全局钩子
    ! 定义全局钩子, 要返回self.cleaned_data的数据
    此时的钩子可以获取所有字段的值
    """


高度


一括追加スタイル

フォームクラスのinitメソッドを書き換えることにより実現しました。

from django.forms import Form

class RegForm(Form):
    test01 = forms.CharField()
    test02 = forms.CharField()
    test03 = forms.CharField()

    def __init__(self, *args, **kwargs):
        super(RegForm, self).__init__(*args, **kwargs)
        for field in iter(self.fields):
            self.fields[field].widget.attrs.update(
                {
                    'class': 'form-control',
                    'placeholder': "test",
                }
            )

モデルフォーム

フォームモデルの終わりと相まって

== ==後のデータベースフィールドを使用してルールを結合

チェックサムファイルを形成します。

from django import forms
from django.core.exceptions import ValidationError  # 用于返回错误信息
from . import models


class BaseForm(forms.ModelForm):
    # 重写父类的init方法来批量添加样式
    def __init__(self, *args, **kwargs):
        super(BaseForm, self).__init__(*args, **kwargs)
        for field in iter(self.fields):
            self.fields[field].widget.attrs.update({"class": "input"})


# 注册Form
class RegForm(BaseForm):

    class Meta:

        # 指定数据表
        model = models.UserProfile

        # 指定要校验的字段,如果指定为 "__all__",则校验所有的字段;如果指定为列表, 则只校验列表内的字段
        fields = ["username", "password", "email"]

        # 提示信息
        labels = {
            "username": "用户名",
            "password": "密码",
            "email": "邮箱",
        }

        # 自定义错误信息
        error_messages = {
            "username": {
                "required": "请输入用户名"
            },
            "password": {
                "required": "请输入密码",
            },
            "email": {
                "required": "请输入邮箱地址",
                "invalid": "邮箱格式错误",
            }
        }

        # 自定义插件
        widgets = {
            "username": forms.widgets.TextInput(
                attrs={
                    "id": "reg_username",
                }
            ),
            "password": forms.widgets.PasswordInput(
                attrs={
                    "id": "reg_password",
                }
            ),  # 指定input框的type类型为password,并添加id属性及值
        }

        # 帮助信息
        help_texts = {}


    # 确认密码
    re_password = forms.CharField(
        label="确认密码",
        error_messages= {
            "required": "",
        },
        widget=forms.widgets.PasswordInput(
            attrs={
                "id": "reg_re_password",
            }
        ),
    )


    # 用于校验密码格式
    def clean_password(self):
        password = self.cleaned_data.get("password")
        if len(password) == 32:  # 前端用md5加密后的固定长度
            return password
        raise ValidationError("密码格式错误!")


    # 用于校验密码一致性
    def clean_re_password(self):
        """
        局部钩子:clean_字段名
        :return: 定义哪个字段的钩子,就得返回哪个字段的值
        """
        password = self.cleaned_data.get("password")
        re_password = self.cleaned_data.get("re_password")
        if not password or password == re_password:  # not password:如果clean_password函数校验失败,则password为空
            return re_password
        raise ValidationError("密码不一致!")


"""
class Meta常见参数如下:

model = models.Student  # 对应的Model中的类
fields = "__all__"  # 字段,如果是__all__,就是表示列出所有的字段;如果是列表, 则只使用列表内的字段
exclude = []  # 排除的字段
labels = None  # 提示信息
help_texts = None  # 帮助提示信息
widgets = None  # 自定义插件
error_messages = None  # 自定义错误信息
"""

ビューのファイル:

# 部分相关的代码如下:

if reg_form.is_valid():  # 成功校验数据后,才可执行reg_form.cleaned_data
    obj = reg_form.save(commit=False)  # Form组件自带的方法,commit=False表示稍后通过obj.save()方法保存数据
    obj.set_password(obj.password)  # 设置用户密码
    obj.blog_path = obj.username
    obj.nickname = obj.username
    obj.save()  # 保存
    # data = reg_form.cleaned_data  # 只有执行了reg_form.is_valid()后才可执行reg_form.cleaned_data

フォーム套フォーム

ビューのファイル:

# 生成每行可编辑的form套form的表单
from django.forms import modelformset_factory  

def study_record(request, course_id):
    FormSet = modelformset_factory(models.StudyRecord, StudyRecordForm, extra=0)
    # 会自动在表单下面多生成一个form > extra=0:不生成
    queryset = models.StudyRecord.objects.filter(course_record_id=course_id)
    form_set = FormSet(queryset=queryset)
    return render(request, 'crm/sutdy_record_list.html', {'form_set': form_set})

HTMLファイル:

{% for form in form_set %}
    <tr>
        {{ form.id }}
        <td style="display: none">{{ form.student }}</td>
        {# style="display: none" 可禁用编辑#}
        <td>{{ forloop.counter }}</td>
        <td>{{ form.instance.student.name }}</td>
        <td>{{ form.attendance }}</td>
        <td>{{ form.score }}</td>
        <td>{{ form.homework_note }}</td>
    </tr>
{% endfor %}

"

オリジナル:http://blog.gqylpy.com/gqy/269

おすすめ

転載: www.cnblogs.com/gqy02/p/11363032.html