1203 forms组件

	多对多三种创建方式
	
	forms校验性组件
	
	django settings源码

昨日内容

ajax结合sweetalert
		自己写一个删除按钮的确认框
	
	去github上下载sweetalert源码 你只需要使用里面dist文件夹
		gitlab
		公司自己搭建
		码云
	
	参考示例书写即可
		
		
	二次开发能力
		基于人家已经写好的功能修改
			1.先看别人的配置参数
			2.前期就是猜
			3.整体修改
	linux
	redis
	mongodb
	github
	git
	
	批量处理
		bulk_create()
		当你要批量操作数据库的时候 一定要减少走数据库的频率
		
	数据的分页展示
		django其实有内置的分页模块
		但是该模块不好用,书写麻烦,功能不健全
		
		自定义分页
			1.queryset支持切片操作
			2.研究当前页 每页展示多少条数据  起始位置 终止位置
			3.前端代码不一定非要在前端书写  后端也可以
		
		把自定义的代码拷贝到本地
			基本使用
				将代码放入到一个py文件中
				
				导入该文件中的类
				
					1.生成该类的对象
						展示数据的总条数
						用户想访问的页码
						默认参数每页展示几条数据
						分页页码的个数 奇数位
					
					2.前端使用
						qeuryset部分
						|safe

多对多三种创建方式

封装程度越高,可扩展性越差

1.全自动

一般情况下

class Book(models.Model):
    title = models.CharField(max_length=32)
    # 多对多字段
    authors = models.ManyToManyField(to='Authors')

class Authors(models.Model):
    name = models.CharField(max_length=32)

好处

  • 自始至终你都没有操作第三张表,全部都是有orm自动帮你创建
  • 内置了四个操作第三张表的方法
    • add
      remove
      set
      clear

缺点

  • 自动创建的第三张表无法扩展和修改字段,表的扩展性较差

2.纯手动

了解

class Book(models.Model):
    title = models.CharField(max_length=32)

class Authors(models.Model):
    name = models.CharField(max_length=32)


# 自建第三张表

class Book2Authors(models.Model):
    book = models.ForeignKey(to='Book')
    author = models.ForeignKey(to='Authors')
    
    # 可以手动创建第三张表中的字段
    create_time = models.DateField(auto_now_add=True)

好处

  • 第三张表中字段个数和字段名称全都可以自己定义

缺点

  • 不再支持orm跨表查询,没有正反向的概念
  • 不能使用修改字段方法
    • add
      remove
      set
      clear

3.半自动through='',through_fields=(外键字段)

推荐使用

# 半自动
class Book(models.Model):
    title = models.CharField(max_length=32)

    # 多对多关系字段
    authors = models.ManyToManyField(to='Authors',through='Book2Authors',through_fields=('authors','book'))


class Authors(models.Model):
    name = models.CharField(max_length=32)


# 自建第三张表
class Book2Authors(models.Model):
    book = models.ForeignKey(to='Book')
    author = models.ForeignKey(to='Authors')
    # 该表中有任意多的外键字段
    
  • through='第三张表名'指定了不自动创建,手动创建的第三张表名,并与之关联
  • through_fields=('','')指定了第三张表中的到底哪两个字段维护表之间多对多关系,外键在哪,哪个字段在前面
当你的ManyToMany只有一个参数to的情况下orm会自动帮你创建第三张表
如果你加了throug和through_fields那么orm就不会自动帮你创建第三张表,但是他会在内部帮你维护关系,让你能够继续使用orm的跨表查询

through		自己制定第三张表关系
through_fields		自己制定第三张表中到底哪两个字段维护这表与表之间的多对多关系,外键在哪个表中,参数放在前面

好处

  • 可以任意的添加和修改第三张表中的字段
  • 支持orm跨表查询

缺点

  • 不支持表字段的修改方法
  • add
    remove
    clear
    set

forms组件

1.简单引入

需求:
    注册页面,获取用户输入的用户名和密码
    提交到后端之后,后端需要对用户名和密码进行校验
    用户名中不能含有'金 瓶 梅'
    密码不能少于三位
    如果不符合,展示响应的错误信息

views

from django.shortcuts import render,HttpResponse,redirect

# Create your views here.


def register(request):
    # get请求来的时候直接走的是空值字典
    errors = {'username':'','password':''}
    # 当请求方式是post时给字典赋值
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        if '金 瓶 梅' in username:
            errors['username'] = '不符合社会主义核心价值观'

        if len(password) < 4:
            errors['password'] = '注意注意太少了'
    return render(request,'register.html',locals())

register.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>简易校验用户的输入功能</title>
    <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
    <link rel="stylesheet" href="bootstrap-3.3.7-dist/css/bootstrap.min.css">
    <script src="bootstrap-3.3.7-dist/js/bootstrap.min.js"></script>

</head>
<body>

<form action="" method="post">
    <p>username
        <input type="text" name="username">
        <span style="color: red">{{ errors.username }}</span>
    </p>
    <p>password
        <input type="text" name="password">
        <span style="color: red">{{ errors.password }}</span>
    </p>
    <input type="submit">
</form>
</body>
</html>

以上代码简单做到的事

  • 手动书写html代码获取用户输入 -- 渲染标签
  • 将数据传递给后端做数据校验 -- 校验数据
  • 如果有数据错误,你还展示了错误信息 -- 展示信息

2.forms组件作用

能够做的事情就是上面的三步

  • 渲染标签
  • 校验数据
  • 展示信息

使用forms组件的第一步,必须先写一个类

from django import  forms

from django import  forms

class MyForm(forms.Form):
    # username字段 最少三位,最多八位
    username = forms.CharField(max_length=8,min_length=3)
    # password字段 最少三位,最多八位
    password = forms.CharField(max_length=8,min_length=3)
    # email字段 必须是邮箱格式
    email = forms.EmailField()

测试用pycharm

右下角 python console
自动创建测试环境

img

2.1 校验数据

实例化创建的类,传入字典,字典中是需要校验的数据,获得对象form_obj

form_obj = views.MyForm({'username':'jason','password':'12','email':'123'})

1.is_vaild 查看是否合法

form_obj.is_valid()

False  # 只有当你的数据全部符合校验规则的情况下 结果才是True 否则都为False

2..errors 查看不符合的字段及原因

form_obj.errors

{
'password': ['Ensure this value has at least 3 characters (it has 2).'],
'email': ['Enter a valid email address.']
}

3.cleaned_data 查看符合的数据

form_obj.cleaned_data

{'username': 'jason'}

4.传值的顺序(少传值与多传值)

img

forms组件中 定义的字段默认都是必须传值的 不能少传

少传了字段会报错
form_obj = views.MyForm({'username':'jason','password':'12345'})

form_obj.is_valid()
False

form_obj.errors
{'email': ['This field is required.']}

forms组件只会校验forms类中定义的字段 如果你多传了 不会有任何影响

多设置字段并不会影响
form_obj = views.MyForm({'username':'jason','password':'12345','email':'123@qq.com','xxx':'嘿嘿嘿'})

form_obj.is_valid()
True

2.2 渲染标签

第一步需要生成一个空的forms类的对象

class MyForm(forms.Form):
	pass
	
	
def index(request):
	第一步需要生成一个空的forms类的对象
    form_obj = MyForm()
    直接将生成的对象传递给前端页面
    return render(request,'index.html',locals())
  • froms组件只会帮你渲染获取用户输入的标签 不会帮你渲染提交按钮 需要你自己手动添加

第一种as_p as_ul as_table

直接将所有的信息一起渲染出来

reg.html

Copy<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
    <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
    <title>Title</title>
</head>
<body>
    <div class="container">
        <div class="row">
            {#第一种渲染方式#}
            <div class="col-md-offset-2 col-md-8">
                <form action="" method="post">
                    {% csrf_token %}
                    {{ form.as_p }}
                    <hr>
                    {{ form.as_table }}
                    <hr>
                    {{ form.as_ul }}
                    <hr>
                    <input type="submit" value="提交" class="btn btn-success">
                </form>
            </div>

        </div>
    </div>
</body>
</html>

这种方式, Django的封装程度太高了, 我们完全不能够自定义样式, 所以它只能用来前期的页面快速搭建以及做测试使用. 最后的渲染结果巨丑无比... 实际基本不考虑它.

img

第二种

单独渲染每一个标签

<p>forms组件渲染标签方式2(不推荐使用,写起来太多)</p>
{#input框的提示信息                 获取input框#}
{{ form_obj.username.label }}{{ form_obj.username }}

当我们使用form对象.字段名字的时候, 可以发现这样只渲染出单独的一个input框. 检查还能发现form组件渲染完毕后的一些规律.

img

第三种

上面这种方式也有一个不好的地方, 就是当字段多了以后, 每一个都需要添加类似的样式, 就比较麻烦, 这时候就需要用到第三种方式

遍历form对象来渲染出标签. 只需要对form对象作出以下小的变化, 就可以达到同样的效果

{% for form in form_obj %}
    <p>{{ form.label }}{{ form }}</p>
{% endfor %}

img

可以定义类的label默认设置来渲染出页面的标签

class RegForm(forms.Form):
    # 接下来的定义需要与模型表的字段类型一一对应
    username = forms.CharField(
        max_length=15,  # 用户名最大长度为15
        min_length=3,  # 用户名的最小长度为3
        label='用户名',  # 渲染出在页面上的标签的名字
    )
    password = forms.CharField(
        max_length=15,  # 密码最大长度为15
        min_length=3,  # 密码的最小长度为3
        label='密码',  # 渲染出在页面上的标签的名字
    )

2.3 展示信息

告诉浏览器不做前端校验 form表单设置novalidate参数即可

<form action="" method="post" novalidate>

如何校验前端用户传入的数据

展示错误信息

views

def index(request):
    # 获得空的forms类对象
    form_obj = MyForm()
    # 校验前端用户传入的数据
    if request.method == 'POST':
        # 获取用户的数据,在request.POST中,forms组件校验数据
        form_obj = MyForm(request.POST)   # 该变量名一定要与上面的变量名一致
        if form_obj.is_valid():
            print(form_obj.cleaned_data)
            return HttpResponse('数据全部')
        else:
            print(form_obj.errors)
    return render(request,'index.html',locals())
    
    
-------------------------------------------------------

index.html

<form action="" method="post" novalidate>
    {% for form in form_obj %}
        <p>
            {{ form.label }}{{ form }}
{#            form 等价于方式2中的对象点字段名(使用.0获取列表中的信心)#}
        <span>{{ form.errors.0 }}</span>
        </p>
    {% endfor %}
    <input type="submit">
</form>

img

参数设置

class MyForm(forms.Form):
    # username字段 最少三位,最多八位
    username = forms.CharField(max_length=8,min_length=3,label='用户名',
                               error_messages={
                                   'max_length':'用户名最长8位',
                                   'min_length':'用户名最短3位',
                                   'required':'用户名不能为空'
                               })
    # email字段 必须是邮箱格式
    email = forms.EmailField(label='邮箱',
                             error_messages={
                                 'required':'邮箱不能为空',
                                 'invalid':'邮箱格式错误'
                             })
  • label= 设置提示信息

  • error_messages={}设置报错信息

    • required 不能为空
    • invalid 邮箱格式
  • validations 内置校验器

    RegexValidator 正则校验

2.4 校验数据补充

内置的校验器

内置的校验器   
    from django.core.validators import RegexValidator   
    	validators=[            
    	RegexValidator(r'^[0-9]+$', '请输入数字'),            
    	RegexValidator(r'^159[0-9]+$', '数字必须以159开头'),         
    	]

钩子函数 HOOK

会在普通校验全部符合后开始校验

上面只靠类型检查明显不符合一些比较复杂的校验, 例如用户名不能包含敏感词, 两次密码需要一致, 这都需要进行校验.

类内部的方法,是一个函数,函数体内你可以写任意的校验

局部钩子 clean_字段值

单独校验某一个字段的

.add_error展示某一字段的错误信息

最后需返回字段数据return username

类中定义函数:
	# 校验用户名中不能含有666
    
    def clean_username(self):
        # 校验通过的数据在 cleaned_data
        username = self.cleaned_data.get('username')
        # 第二层的判断
        if '666' in username:
            # 给username字段对应的框显示错误信息
            self.add_error('username','后面的是报错')
        # 将username数据返回
        return username

全局钩子 clean

校验多个字段之间的关系的

return全局的数据return self.cleaned_data

类中
	# 校验两次密码是否一致
	
    def clean(self):
        password = self.cleaned_data.get('password')
        re_password = self.cleaned_data.get('re_password')
        if not password == re_password:
            self.add_error('re_password','两次密码不一致')
        # 将全局的数据返回
        return self.cleaned_data

补充知识点

小猿取经博客园密码
	xiaoyuanqujing@666

其他字段及参数

其他字段属性

  • lable 设置input对应的提示信息

  • initial 给input框设置默认值

  • required 默认为True,控制字段是否为空

  • widget 设置密码文本的显示方式

    • widget=forms.widgets.PasswordInput()

      from django.forms import widgets
      
      widget=forms.widgets.PasswordInput()
      
    • widget=forms.widgets.TextInput()

      括号内可以设置类内的属性 填写字典{},添加多个参数空格连接
      
      widget=forms.widgets.TextInput({'class':'form-control c1 c2','username':'jack'})
      

initial

初始值,input框里面的初始值。

class LoginForm(forms.Form):
    username = forms.CharField(
        min_length=8,
        label="用户名",
        initial="张三"  # 设置默认值
    )
    pwd = forms.CharField(min_length=6, label="密码")

error_messages

重写错误信息。

class LoginForm(forms.Form):
    username = forms.CharField(
        min_length=8,
        label="用户名",
        initial="张三",
        error_messages={
            "required": "不能为空",
            "invalid": "格式错误",
            "min_length": "用户名最短8位"
        }
    )
    pwd = forms.CharField(min_length=6, label="密码")

password

class LoginForm(forms.Form):
    ...
    pwd = forms.CharField(
        min_length=6,
        label="密码",
        widget=forms.widgets.PasswordInput(attrs={'class': 'c1'}, render_value=True)
    )

radioSelect

单radio值为字符串

class LoginForm(forms.Form):
    username = forms.CharField(
        min_length=8,
        label="用户名",
        initial="张三",
        error_messages={
            "required": "不能为空",
            "invalid": "格式错误",
            "min_length": "用户名最短8位"
        }
    )
    pwd = forms.CharField(min_length=6, label="密码")
    gender = forms.fields.ChoiceField(
        choices=((1, "男"), (2, "女"), (3, "保密")),
        label="性别",
        initial=3,
        widget=forms.widgets.RadioSelect()
    )

单选Select

class LoginForm(forms.Form):
    ...
    hobby = forms.ChoiceField(
        choices=((1, "篮球"), (2, "足球"), (3, "双色球"), ),
        label="爱好",
        initial=3,
        widget=forms.widgets.Select()
    )

多选Select

class LoginForm(forms.Form):
    ...
    hobby = forms.MultipleChoiceField(
        choices=((1, "篮球"), (2, "足球"), (3, "双色球"), ),
        label="爱好",
        initial=[1, 3],
        widget=forms.widgets.SelectMultiple()
    )

单选checkbox

class LoginForm(forms.Form):
    ...
    keep = forms.ChoiceField(
        label="是否记住密码",
        initial="checked",
        widget=forms.widgets.CheckboxInput()
    )

多选checkbox

class LoginForm(forms.Form):
    ...
    hobby = forms.MultipleChoiceField(
        choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
        label="爱好",
        initial=[1, 3],
        widget=forms.widgets.CheckboxSelectMultiple()
    )

choice字段注意事项

在使用选择标签时,需要注意choices的选项可以配置从数据库中获取,但是由于是静态字段 获取的值无法实时更新,需要重写构造方法从而实现choice实时更新。

方式一:

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):
        super(MyForm,self).__init__(*args, **kwargs)
        # self.fields['user'].choices = ((1, '上海'), (2, '北京'),)
        # 或
        self.fields['user'].choices = models.Classes.objects.all().values_list('id','caption')

方式二:

from django import forms
from django.forms import fields
from django.forms import models as form_model

 
class FInfo(forms.Form):
    authors = form_model.ModelMultipleChoiceField(queryset=models.NNewType.objects.all())  # 多选
    # authors = form_model.ModelChoiceField(queryset=models.NNewType.objects.all())  # 单选
posted @ 2019-12-03 20:51  fwzzz  阅读(174)  评论(0编辑  收藏  举报