Python学习---DjangoForm的学习

DjangoForm之创建工程

Form是什么东西:

      用于验证用户请求数据合法性的一个组件

普通的Form提交的弊端:

    1.用户提交数据的验证

    2.前台需要进行错误信息的提示

    3.需要保留上次用户输入的信息

# 此处是正常的Form的判断操作
"""
def Login(request):
    if request.method == "GET":
        return render(request, 'login.html')
    elif request.method == "POST":
        # 如果用户输入了10条数据,则Form里需要写10个get来获取值
        user = request.POST.get("user")
        passwd = request.POST.get('passwd')
        email = request.POST.get('email')
        # 判断用户的输入[涉及用户的为空判断,输入格式内容校验以及数据库操作等判断]
        # 数据库校验: 传入参数校验  + 字典的传入校验  **kwargs
        #  filter(user=u, email=e,passwd=p)   ==> filter(**kwargs) 
        #  create(user=u, email=e,passwd=p)   ==> create(**kwargs)
        # 如果校验失败,页面需要给用户显示错误信息,不能redirect[form提交页面会刷新,上次数据无法保留,ajax不涉及]
        只能return render(request, 'login.html; 'args'arg),需要给前台HTML添加{{msg}}操作
"""

查看Django为我们创建的正则:

image

DjangoForm的Form验证

Django的Form验证
    - 控诉:
        a. 用户提交数据的验证
            1、创建模版                      class LoginForm(forms.Form):...
            2、将请求交给模版,创建一个对象  obj = LoginForm(request.POST)
            3、进行验证                       obj.is_valid()【必须执行,这里开始校验,否则clean获取不到值】
            4、获取正确信息                  obj.clean()          
            5、获取错误信息                  obj.errors
        b. 错误信息提示[传递Form对象给后台]
            Form提交,刷新页面的特性,DjangoForm模版对象内部值丰富,再显示时,值和错误信息都有           
        c. 保留上一次提交的数据
            1、自动生成html标签【实际上{{obj.user}} 就是内部生成了一个HTML的字符串】
            2、保留上一次提交的数据【input框的value值更改为上次提交的值即可】       
注:
    obj对象里面有正确信息也有错误信息
    Form使用 a,b,c
    ajax使用 a,错误信息处理: as_json()    as_data()

DjangoForm之前台参数校验实例

settings.py

INSTALLED_APPS = [
   ...
 'app01',   # 注册app
]
STATICFILES_DIRS = (os.path.join(BASE_DIR, "statics"),)  # 现添加的配置,这里是元组,注意逗号
TEMPLATES = [
   ...
   'DIRS': [os.path.join(BASE_DIR, 'templates')],
]

urls.py

from django.contrib import admin
from django.urls import path
from django.conf.urls import url, include
from app01 import views
urlpatterns = [
   path('admin/', admin.site.urls),
   url(r'login.html/', views.Login),
]

views.py

from django.shortcuts import render, redirect
# 创建模板
# 本质是从请求中获取数据后来进行校验
from django import forms
class LoginForm(forms.Form):
    # 前台Form表单里面的name属性的值必须跟这里的名称完全一致,这样数据提交后才能进行校验
    # 如果名称不一致,则默认数据未传递过来,不作处理
    # 如果传递多个参数,则模版默认只按照名称来进行匹配,有则匹配,无责不匹配
    user = forms.CharField(min_length=6)     # 模版元素
    passwd = forms.CharField(min_length=12)  # 模版元素
    email = forms.EmailField(error_messages={"required": "格式错误"})# 模版元素同时自定义格式
"""
    code:
        required:   如果输入为空的时候显示
        invalid:    输入的类型错误
        min_length: 最小长度
"""
def Login(request):
    if request.method == "GET":
        return render(request, 'login.html')
    elif request.method == "POST":
        # 模版会自动从request里面取值并校验
        obj = LoginForm(request.POST)
        # 从模版里面开始验证,全部正确则显示结果正确,否则错误
        status = obj.is_valid()
        print('验证结果:', status)
        if status:
            # 获取校验过的值和验证的错误信息
            value_dict = obj.clean()
            print('验证通过的值:', value_dict)
            # 类.create(**value_dict)  --> 此时可以直接插入数据到数据库了
        else:
            error_dict = obj.errors  # 此时的返回结果是个ErrorDict对象,可以type看类型
     # <class 'django.forms.utils.ErrorDict'>该对象基础DICT这个里面有as_json和as_data方法
            print('错误的信息[默认UL显示]:', error_dict)
            error_dict_json = obj.errors.as_json()  # 此时的返回结果是个JSON集
            print('错误的信息[json显示]:', error_dict_json)
        return render(request, 'login.html',{'obj': obj})

templates/login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
</head>
<body>
    <h1>Form提交数据</h1>
    <form method="post" action="/login.html/">
                 <!-- 前台的属组操作只能用点.来获取列表的第一个元素 -->
        <p><input type="text" name="user" placeholder="用户名"><span>{{ obj.user.errors.0}}</span></p>
   <p><input type="password" name="passwd" placeholder="密码"><span>{{ obj.passwd.errors.0}}</span></p>
         <p><input type="text" name="email" placeholder="邮箱"><span>{{ obj.user.email.0}}</span></p>
        <input type="submit" value="Form提交">
        <input id='ajax_submit' type="button" value="Ajax提交">
    </form>
</body>
<script src="/static/jquery-2.1.4.min.js"></script>
<script>
    $(function () {
        $('#ajax_submit').click(function () {
            $.ajax({
                url:"/login.html",
                data:{user:'omc', email:'omc@hhh.com', passwd:'lem600'},
                type:'POST',
                success:function (args) {
                    console.log(args)
                }
            })
        })
    })
</script>
</html>

页面显示:

image

image

学习扩展:

# 封装Django里面的所有错误信息

error_dict = obj.errors  # 此时的返回结果是个ErrorDict对象
print('错误的信息[UL显示]:', error_dict) # 这里返回的是一个对象
print('错误信息类型:', type(error_dict))#因为返回了ErrorDict里面__str__方法:return self.as_ul();
# 因为返回的是DICT对象,所以可以利用key获取
print('错误信息类型:', type(error_dict)) # 错误信息类型: <class 'django.forms.utils.ErrorDict'>
#print('获取错误信息[属性获取]:', error_dict.user)   # 错误,'ErrorDict' object has no attribute 'user'
print('获取错误信息[key获取]:', error_dict['user']) # 正确
print('获取错误信息[key获取]类型:', type(error_dict['user']))  # ErrorList类型,默认返回第一个list[0]
print('获取错误信息[此时是字符串]:', error_dict['user'][0]) # 字符串 This field is required.

image

DjangoForm之提交数据后保留数据

   Django会自动生成HTML,并保留我们生成的数据

settings.py

INSTALLED_APPS = [
   ...
 'app01',   # 注册app
]
STATICFILES_DIRS = (os.path.join(BASE_DIR, "statics"),)  # 现添加的配置,这里是元组,注意逗号
TEMPLATES = [
   ...
   'DIRS': [os.path.join(BASE_DIR, 'templates')],
]

urls.py

from django.contrib import admin
from django.urls import path
from django.conf.urls import url, include
from app01 import views
urlpatterns = [
   path('admin/', admin.site.urls),
   url(r'login.html/', views.Login),
]

views.py

from django.shortcuts import render, redirect
# 创建模板
# 本质是从请求中获取数据后来进行校验
from django import forms
class LoginForm(forms.Form):
    # 前台Form表单里面的name属性的值必须跟这里的名称完全一致,这样数据提交后才能进行校验
    # 如果名称不一致,则默认数据未传递过来,不作处理
    # 如果传递多个参数,则模版默认只按照名称来进行匹配,有则匹配,无责不匹配
    user = forms.CharField(min_length=6)     # 模版元素
    passwd = forms.CharField(min_length=12)  # 模版元素
    email = forms.EmailField(error_messages={"required": "格式错误"})# 模版元素同时自定义格式
"""
    code:
        required:   如果输入为空的时候显示
        invalid:    输入的类型错误
        min_length: 最小长度
"""
def Login(request):
    if request.method == "GET":
       obj = LoginForm()  # 这里生成的obj对象只有生成HTML的作用,但是名称必须跟后面POST对象一致
       return render(request, 'login.html', {'obj': obj})
    elif request.method == "POST":
        # 模版会自动从request里面取值并校验
        obj = LoginForm(request.POST)
        # 从模版里面开始验证,全部正确则显示结果正确,否则错误
        status = obj.is_valid()
        print('验证结果:', status)
        if status:
            # 获取校验过的值和验证的错误信息
            value_dict = obj.clean()
            print('验证通过的值:', value_dict)
            # 类.create(**value_dict)  --> 此时可以直接插入数据到数据库了
        else:
            error_dict = obj.errors  # 此时的返回结果是个ErrorDict对象,可以type看类型
     # <class 'django.forms.utils.ErrorDict'>该对象基础DICT这个里面有as_json和as_data方法
            print('错误的信息[默认UL显示]:', error_dict)
            error_dict_json = obj.errors.as_json()  # 此时的返回结果是个JSON集
            print('错误的信息[json显示]:', error_dict_json)
        return render(request, 'login.html',{'obj': obj})

templates/login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
</head>
<body>
    <h1>Form提交数据</h1>
    <form method="post" action="/login.html/">
                                                              <!-- 前台的属组操作只能用点.来获取,这里的表单是Django帮我们做的 -->
        <p>{{ obj.user }}<span>{{ obj.user.errors.0}}</span></p>
        <p>{{ obj.passwd }}<span>{{ obj.passwd.errors.0}}</span></p>
        <p>{{ obj.email }}<span>{{ obj.user.email.0}}</span></p>
        <input type="submit" value="Form提交">
        <input id='ajax_submit' type="button" value="Ajax提交">
    </form>
</body>
<script src="/static/jquery-2.1.4.min.js"></script>
<script>
    $(function () {
        $('#ajax_submit').click(function () {
            $.ajax({
                url:"/login.html",
                data:{user:'omc', email:'omc@hhh.com', passwd:'lem600'},
                type:'POST',
                success:function (args) {
                    console.log(args)
                }
            })
        })
    })
</script>
</html>

页面显示;

image

问题:为什么get的Form对象必须和Form的一致?

答: get请求过来后我们实例化了一个不带参数的LoginForm的obj对象,此时的只能在前台生成HTML作用[前台obj.user]

   post请求提交数据后,我们实例化了一个带POST参数的LoginForm的obj对象,里面有我们前台请求的数据,此时obj对象具有1.生成前台HTML的作用 2.带了post参数可以直接前台显示 3.我们前台用来同一个模板{{  }}来接收数据【正确/错误信息】,所以obj对象的名称不能改

如果我们更改POST对象名称为obj1,前台也更改为obj1,此时数据提交后就不再显示input框了,因为一个是obj,一个是obj1

附:input标签的生成过程[源码分析]

image

DjangoForm的Ajax验证【代码有问题】

settings.py

INSTALLED_APPS = [
   ...
 'app01',   # 注册app
]
STATICFILES_DIRS = (os.path.join(BASE_DIR, "statics"),)  # 现添加的配置,这里是元组,注意逗号
TEMPLATES = [
   ...
   'DIRS': [os.path.join(BASE_DIR, 'templates')],
]

urls.py

from django.contrib import admin
from django.urls import path
from django.conf.urls import url, include
from app01 import views
urlpatterns = [
   path('admin/', admin.site.urls),
   url(r'login.html/', views.Login),
   url(r'^login_ajax.html', views.login_ajax),
]

views.py

from django.shortcuts import render
from django.shortcuts import HttpResponse
import json
def login_ajax(request):
    if request.method == "GET":
        return render(request, 'login_ajax.html')
    elif request.method == "POST":
        ret = {'status': True, 'error':None, 'data': None}
        obj = LoginForm(request.POST)
        if obj.is_valid():
            print(obj.clean())
        else:
            # 方式一
            # res_str = obj.errors.as_json() # res_str是一个字符串
            # ret['status'] = False
            # ret['error'] = res_str
            # 两次反序列化
            # 方式二:将Django的ValidationError类型转换为JSON对象
            ret['status'] = False
            ret['error'] = obj.errors.as_data() #Djaongo的数据类型 {'user': [ValidationError(['用户名长度不能小6'])], 'email': [ValidationError(['邮箱格式错误'])]}
            # 一次反序列化
        return HttpResponse(json.dumps(ret, cls=JsonCustomEncoder))

# 方式一不需要此类
from django.core.validators import ValidationError
class JsonCustomEncoder(json.JSONEncoder):
    def default(self, field):
        if isinstance(field, ValidationError):
            return {'code': field.code, 'message': field.message}
        else:
            return json.JSONEncoder.default(self, field)

templates/login_ajax.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        .error-msg{
            color: red;
            font-size: 12px;
        }
    </style>
</head>
<body>
    <h1>Form提交数据</h1>
    <form id="f1">
        <p>        <input id="u" type="text" name="user" placeholder="用户名" />    </p>
        <p>        <input id="e" type="text" name="email" placeholder="邮箱" />    </p>
        <p>        <input id="p" type="text" name="pwd" placeholder="密码" />    </p>
        <input id="ajax_submit" type="button" value="Ajax提交"  />
    </form>
    <script src="/static/jquery-2.1.4.min.js"></script>
    <script>
        $(function () {
            $('#ajax_submit').click(function () {
                $.ajax({
                    url:"/login_ajax.html",
                    //data: {user: $('#u').val(), email: $('#e').val(), pwd: $('#p').val()},
                    data: $('#f1').serialize(),
                    type: 'POST',
                    success:function (arg) {
                        $('.error-msg').remove();
                        var v1 = JSON.parse(arg);  //解析JSON数据
                        console.log(v1);
                        if(!v1.status){
                            // var error_obj = JSON.parse(v1.error);
                            var error_obj = v1.error;
                            $.each(error_obj,function (k,v) {
                                // k: user 或 email
                                // v: [{}{}{},]
                                var tag = document.createElement('span');
                                tag.className = 'error-msg';
                                tag.innerHTML = v[0].message;
                                $("input[name='" + k +"']").after(tag);
                            })
                        }else{
                            location.href = "/inde.html"
                        }
                        // { 'stauts': true, 'error':xx, 'data':’‘}
                    }
                })
            })
        })
    </script>
</body>
</html>

页面显示;

image

DjangoForm更多用法之多选框

settings.py

INSTALLED_APPS = [
   ...
 'app01',   # 注册app
]
STATICFILES_DIRS = (os.path.join(BASE_DIR, "statics"),)  # 现添加的配置,这里是元组,注意逗号
TEMPLATES = [
   ...
   'DIRS': [os.path.join(BASE_DIR, 'templates')],
]

urls.py

from django.contrib import admin
from django.urls import path
from django.conf.urls import url, include
from app01 import views
urlpatterns = [
        path('admin/', admin.site.urls),
        url(r'^index.html', views.index),
        url(r'^edit_index.html', views.edit_index), 
]

views.py

from django.shortcuts import render
from django.shortcuts import HttpResponse
class IndexForm(forms.Form):
    # 模版中的元素
    user = forms.CharField(min_length=6,error_messages={"required": '用户名不能为空','min_length': '用户名长度不能小6'})
    email = forms.EmailField(error_messages={"required": '邮箱不能为空','invalid': '邮箱格式错误'})
   favor = forms.MultipleChoiceField( choices=[(1,'AAA'),(2,'BBB'),(3,'CCC')]    )
def index(request):
    obj = IndexForm()
    return render(request,'index.html',{'obj': obj})
def edit_index(request):
    obj = IndexForm({'user': 'root','email': 'hhh@666.com','favor': [2,3]})
    return render(request,'index.html',{'obj': obj})

templates/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <p>{{ obj.user }}</p>
    <p>{{ obj.email }}</p>
    <p>{{ obj.favor }}</p>
</body>
</html>

DjangoForm更多用法之widget插件基本使用

settings.py

INSTALLED_APPS = [
   ...
 'app01',   # 注册app
]
STATICFILES_DIRS = (os.path.join(BASE_DIR, "statics"),)  # 现添加的配置,这里是元组,注意逗号
TEMPLATES = [
   ...
   'DIRS': [os.path.join(BASE_DIR, 'templates')],
]

urls.py

from django.contrib import admin
from django.urls import path
from django.conf.urls import url, include
from app01 import views
urlpatterns = [
   # 带插件的Form
 url(r'^detail.html', views.Detail),
]

views.py

from django.shortcuts import render, redirect

from django import forms          # forms里面引用了field,widget的内容
from django.forms import fields   # 这里再次引用是为了更加明确而已
from django.forms import widgets
# 带插件的Form,这里是定义模板
class DetailForm(forms.Form):
    # user = fields.CharField() 默认widget = TextInput;此时就是一个白框,里面输入的文字都是明文【字符串】
    # 自定义样式: attrs={'class': 'c1'} 此时就告诉Django,我要给生成的标签添加了样式class=c1
    user = fields.CharField(widget=widgets.PasswordInput(attrs={'class': 'c1', 'placeholder': '请输入密码'}))
    # choices接收的是列表,列表里面是元组,里面2个值[第一个参数是value值,第二个是]
    choice = fields.ChoiceField(choices=[(1, '北京'), (2, '南京'), (3, '天津')])
    # Django可以把前台的字符串转换为数字类型
    age = fields.IntegerField()  
    # 总结: 如果是个单值[字符串],直接获取用户输入的字符串,  ---> CharField()[获取字符串]
    # 如果是个单值[数  字],直接获取用户输入的数字,  ---> IntegerField(),Django帮我们字符串换Int类型
    #        如果是个多值[下拉框],直接获取用户选择的字符串,  ---> ChoiceField()[获取的是字符串]
    # 前台返回的只有3类:字符串,数字, 列表

def Detail(request):
    obj = DetailForm()
    return render(request, 'detail.html', {'obj': obj})

templates/detail.html、

<!DOCTYPE html>
<html lang="en">
<head>    <meta charset="UTF-8">  </head>
<body>
    {{ obj.user }}
    {{ obj.choice }}
</body>
</html>

页面显示;

image

学习拓展:

choice = fields.ChoiceField(choices=[(1, '北京'), (2, '南京'), (3, '天津')])
new_choice = fields.CharField(widget=widgets.Select(choices=[(1, '北京'), (2, '南京'), (3, '天津')]))
int_choice = fields.IntegerField(widget=widgets.Select(choices=[(1, '北京'), (2, '南京'), (3, '天津')]))
radio_select = fields.CharField(widget=widgets.RadioSelect(choices=[(1, '北京'), (2, '南京'), (3, '天津')]))

CharField也可以利用插件实现select的效果,所以ChoiceField实际上是new_choice一系列的简写

Choice和new_choice的返回结果是字符串

Int_choice的返回结果是整数类型

最强大的还是CharField,虽然生成的text文本框,但是可以通过插件实现转换其他HTML样式

DjangoForm更多用法之字段和插件更多使用

settings.py

INSTALLED_APPS = [
   ...
 'app01',   # 注册app
]
STATICFILES_DIRS = (os.path.join(BASE_DIR, "statics"),)  # 现添加的配置,这里是元组,注意逗号
TEMPLATES = [
   ...
   'DIRS': [os.path.join(BASE_DIR, 'templates')],
]

urls.py

from django.contrib import admin
from django.urls import path
from django.conf.urls import url, include
from app01 import views
urlpatterns = [
    # 带插件的Form
    url(r'^detail.html', views.Detail),
    url(r'^fieldForm.html', views.DetailField), 
]

views.py

from django.shortcuts import render, redirect

from django import forms          # forms里面引用了field,widget的内容
from django.forms import fields   # 这里再次引用是为了更加明确而已
from django.forms import widgets
from django.core.validators import RegexValidator
# 字段的详细使用
class FieldForm(forms.Form):
    f = fields.CharField(
        required=True,     # 是否必须填写, 默认是必填的,
        max_length=8,      # 最大长度限制
        min_length=6,      # 最小长度限制
        label='用户名',    # 用于前端显示用的标签 obj.f.label  自带属性; 也可用obj.f.label_tag实现自动写入
        initial='用户名',   # 文本框内的初始值; views里面注意区别GET和POST请求,initial默认是GET请求显示
        show_hidden_initial='初始隐藏的值',  # 显示一个隐藏的标签,可以判断输入的值和隐藏的值是否有区别,然后处理
        validators=[RegexValidator(r'^[0-9]+$', 'phoneNumber must be digital', code='phoneNumberError'), ],  # 自定义验证规则
        error_messages={'required': '不能为空', 'invalid': '格式错误', 'max_length': '格式太长了'},  # 不指定则显示默认的
        disabled=True,  # 默认disabled=False,表示文本框可以编辑
        label_suffix='--->',  # label的后缀,默认是冒号,这里更改为 --->
    )
    '''
        注意: error_messages里面通过code来进行错误信息的匹配
               想覆盖原来英文的错误信息,在error_messages覆盖即可
               error_messages的优先级别高于自定义的优先级,且根据code来进行匹配
               error_messages可以根据前面有什么参数[eg,min_length],message的code就可以写什么[这里就是min_length]
               最常用的2个: required, invalid   max_length   min_length 
    '''
    # 另一种方式实现自定义正则[第一种是上述的CharField里面的的validator]
    f2 = fields.RegexField(r'^[0-9]+$')
    '''
    文件上传:
        1.form表单需要使用enctype="multipart/form-data"
        2.后台需要request.Files来接收文件,  obj = FieldForm(request.POST, request.FILES)
        3.获取文件对象InMemoryUploadedFile[对象内有文件名称,文件大小,文件内容]
    '''
    f3 = fields.FileField(allow_empty_file=False) # 文件不允许为空
    # 设置下拉框,此时默认返回的是字符串类型
    f4 = fields.ChoiceField(
        initial=2,      # 设置默认值,单选的时候只能选择1个默认值哈
        choices=((1, 'AAA'), (2, 'BBB'), (3, 'CCC')),  # 设置下拉选项[可迭代的就行]此时返回的1,2,3是字符串'1','2','3'
    )
    # 自带类型转换的Choice
    f5 = fields.TypedChoiceField(
        coerce=lambda x: int(x),  # 传递的参数转换为int类型;  lambda的等号[=]2边不需要空格
        initial=2,  # 设置默认值,单选的时候只能选择1个默认值哈
        choices=((1, 'AAA'), (2, 'BBB'), (3, 'CCC')),  # 设置下拉选项[可迭代的就行]此时返回的1,2,3是字符串'1','2','3'
    )
    # 设置下拉框多选
    f6 = fields.MultipleChoiceField(
        initial=(2, 3),  # 设置默认值,必须是可迭代的就行
        choices=((1, 'AAA'), (2, 'BBB'), (3, 'CCC')),  # 设置下拉选项[可迭代的就行]此时返回的1,2,3是字符串'1','2','3'
    )
    # 实现多个验证[既满足A又满足B]
    f7 = fields.ComboField(fields=[fields.CharField(max_length=20), fields.EmailField(), ])  # 里面是个可迭代对象

    # 抽象类,子类中可以实现聚合多个字典去匹配一个值,要配合MultiWidget使用
    f8 = fields.MultiValueField(fields=[fields.ChoiceField(), ])  # 里面是可迭代对象
    # 生成2个框,因为继承了MultiValueField[这个类中有2个定制的CharField]
    f9 = fields.SplitDateTimeField()
    # 文件选项:此时会把当前app01路径下的所有文件以下拉框的形式显示[提交也是提交选中选项]
    f10 = fields.FilePathField(path='app01',
                               match=None,           # 正则匹配
                               recursive=False,      # 递归下面的文件夹
                               allow_files=True,     # 是否允许文件
                               allow_folders=False,  # 是否允许文件夹等其他属性)
                               )
    # IP的验证
    f11 = fields.GenericIPAddressField()
    # 只允许数字,字母,下划线
    f12 = fields.SlugField()           # 数字,字母,下划线,减号(连字符)
    # UUID
    f13 = fields.UUIDField()

def DetailField(request):
    if request.method == "GET":
        obj = FieldForm()
        return render(request, 'fieldForm.html', {'obj': obj})
    else:
        obj = FieldForm(request.POST, request.FILES)  # 注意别忘了参数,因为is_valid和clean都是POST请求的
        obj.is_valid()
        data = obj.clean()
        error_json = obj.errors.as_json()
        print("正确信息:", data)
        print("错误信息:", error_json)
        return render(request, 'fieldForm.html', {'obj': obj})

templates/fieldForm.html、

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
</head>
<body>
    <form action="/fieldForm.html/" method="post" enctype="multipart/form-data">
        <h2>{{ obj.f.id_for_label }} 是个字符串,自动生成了一个id,这里自定制label效果</h2>
        <label for="{{ obj.f.id_for_label }}">{{ obj.f.label }}:</label>{{ obj.f }} <hr>
        <h2> {{ obj.f.label_tag }}可以自动帮我们生成label标签,等价上面的全部  </h2>
        {{ obj.f.label_tag }}{{ obj.f }}<hr>
        <h2>第二种自定义正则</h2>
        {{ obj.f2 }}<hr>
        <h2>文件上传</h2>
        {{ obj.f3 }}<hr>
        <h2>下拉框</h2>
        {{ obj.f4 }}<hr>
        <h2>多选下拉框</h2>
        {{ obj.f6 }}
        <input type="submit" value="提交">
    </form>
</body>
</html>

页面显示[不全显示];

image

  DjangoForm应用-- select数据从数据库取且实时刷新

settings.py

INSTALLED_APPS = [
   ...
 'app01',   # 注册app
]
STATICFILES_DIRS = (os.path.join(BASE_DIR, "statics"),)  # 现添加的配置,这里是元组,注意逗号
TEMPLATES = [
   ...
   'DIRS': [os.path.join(BASE_DIR, 'templates')],
]

urls.py

from django.contrib import admin
from django.urls import path
from django.conf.urls import url, include
from app01 import views
urlpatterns = [
     # select的数据从数据库来,且实时更新
  url(r'^db.html', views.db), 
]

views.py

from django.shortcuts import render, redirect

from django import forms          # forms里面引用了field,widget的内容
from django.forms import fields   # 这里再次引用是为了更加明确而已
from django.forms import widgets
from django.core.validators import RegexValidator

from app01.models import DBModel
class DBForm(forms.Form):
    d1 = fields.CharField()
    # 固定的option
    type1 = fields.ChoiceField(choices=[(1, 'AAA'), (2, 'BBB'), (3, 'CCC')])
    # 从数据库内获取option
    type2 = fields.ChoiceField(choices=DBModel.objects.all().values_list())  # 将数据转换为元组类型的list
    # 实时刷新数据库内容
    type3 = fields.ChoiceField(choices=[]) # 数据从数据库读取一次,每次生成对象都从内存获取,易产生脏数据

    def __init__(self, *args, **kwargs):   # 调用父级别的构造方式,每次创建对象的时候都会获取数据
        super(DBForm, self).__init__(*args, **kwargs)
        self.fields['type3'].choices = DBModel.objects.all().values_list() # 数据从此处获取

def db(request):
    # 手动在数据库内创建数据库数据  --> 图形界面提交
    if request.method == "GET":
        obj = DBForm()
        return render(request, 'db.html', {'obj': obj})
    else:
        obj = DBForm(request.POST, request.FILES)  # 注意别忘了参数,因为is_valid和clean都是POST请求
        obj.is_valid()
        data = obj.clean()
        error_json = obj.errors.as_json()
        print("正确信息:", data)
        print("错误信息:", error_json)
        return render(request, 'db.html', {'obj': obj})

app01/models.py

from django.db import models
# Create your models here.
class DBModel(models.Model):
    type = models.CharField(max_length=22)  #  创建type字段且id是Django帮我们创建

templates/db.html、

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
</head>
<body>
            用户名: {{ obj.d1 }}<br>
            固定的: {{ obj.type1 }}<br>
            数据库: {{ obj.type2 }}<br>
实时刷新数据库内容:  {{ obj.type3 }}<br>
</body>
</html>

初始化数据库:

python manage.py makemigrations
python manage.py migrate

页面显示[不全显示]

image

数据库内容:

image

DjangoForm应用--新URL方式编辑时,默认内容选中

settings.py

INSTALLED_APPS = [
   ...
 'app01',   # 注册app
]
STATICFILES_DIRS = (os.path.join(BASE_DIR, "statics"),)  # 现添加的配置,这里是元组,注意逗号
TEMPLATES = [
   ...
   'DIRS': [os.path.join(BASE_DIR, 'templates')],
]

urls.py

from django.contrib import admin
from django.urls import path
from django.conf.urls import url, include
from app01 import views
urlpatterns = [
# 新URL方式编辑时,且内容默认选中
url(r'^dbEdit.html', views.dbEdit),
]

views.py

from django.shortcuts import render, redirect

from django import forms          # forms里面引用了field,widget的内容
from django.forms import fields   # 这里再次引用是为了更加明确而已
from django.forms import widgets
from django.core.validators import RegexValidator

from app01 import models
class DBEditForm(forms.Form):
    user = fields.CharField()
    user_type1 = fields.IntegerField(widget=widgets.Select(choices=[(1, 'AAA'), (2, 'BBB'), (3, 'CCC')]))
    user_type2 = fields.IntegerField(widget=widgets.Select(choices=[]))
    def __init__(self, *args, **kwargs):
        super(DBEditForm, self).__init__(*args, **kwargs)
        self.fields['user_type2'].widget.choices = DBModel.objects.all().values_list()
# 新URL方式编辑时,默认选中
def dbEdit(request):
    if request.method == "GET":
        nid = request.GET.get('nid')   # 前台定义的nid
        info = models.UserInfo.objects.filter(id=nid).first()
        print('用户姓名:', info.usename, '\n用户类型:', info.type_id)
        '''
            如果这里的字典dic跟DBEditForm里面的字段一致,则Django默认会帮我们填补数据的
            方案一: 自定义固定的内容:这里采用自定义,info我们转换为字典同理同效果
                dic = {'user': 'root2020', 'user_type1': 3, 'user_type2': 5} 
                obj = DBEditForm(dic)
            方案二: 将info对象转换为字典,根据前台的nid动态的获取内容
                dic = {'user': 'root2020', 'user_type1': 3, 'user_type2': 5}
            注意: 如果是多选的话,则只需要返回一个列表即可
                dic = {'user': 'root2020', 'user_type1': 3, 'user_type2': 5, 'favor':[1,2,3,4]}
        '''
          dic = {'user': info.usename, 'user_type1': 3, 'user_type2': info.type_id}  # 根据前台的反馈来进行数据匹配
        obj = DBEditForm(dic)
        return render(request, 'dbEdit.html', {'obj': obj})
    else:
    obj = DBEditForm(request.POST, request.FILES)  # 注意别忘了参数,因为is_valid和clean都是POST请求的
        obj.is_valid()
        data = obj.clean()
        error_json = obj.errors.as_json()
        print("正确信息:", data)
        print("错误信息:", error_json)
        return render(request, 'dbEdit.html', {'obj': obj})

app01/models.py

from django.db import models
# Create your models here.
class DBModel(models.Model):
    type = models.CharField(max_length=22)  #  创建type字段且id是Django帮我们创建

class UserInfo(models.Model):
    usename = models.CharField(max_length=22)
    # type在数据库内显示的值为: type_id
    type = models.ForeignKey("DBModel", on_delete=True)   # 设置外键,一对多,这里是多的一方

templates/ dbEdit.html

<!DOCTYPE html>
<html lang="en">
<head>    <meta charset="UTF-8">  </head>
<body>
    {{ obj.user }}<br>
    {{ obj.user_type1 }}<br>
    {{ obj.user_type2 }}<br>
</body>
</html>

初始化数据库:

python manage.py makemigrations
python manage.py migrate

页面显示

image

数据库内容

image

 

【更多参考】http://www.cnblogs.com/wupeiqi/articles/6144178.html

posted @ 2018-08-02 08:17  小a玖拾柒  阅读(342)  评论(0编辑  收藏  举报