Django form组件、序列化

一、form组件的作用

1、对用户请求的验证

2、生成HTML代码

3、初始化默认值

二、一个简单的form组件

需要先引入所需要的库:

from django import forms
from django.forms import fields

通过类的方式实现form组件:

class checkForm(forms.Form):    # 需要继承这个类
    #  这里的变量值是前端页面的name属性的值,为了方便使用,这里的名字也要和数据库的字段名一致。
    name = field.CharField(max_length=8)   # 定义了一个文本框,返回值类型是字符型,最大长度是8
            
    age = field.IntegerField(min_length=2)  #  定义了一个文本框,返回值类型是整型,最大长度是8

    Email = field.EmailField(required=True) # 定义了一个文本框,要求是必填项

视图函数的调用:

def index(request):
    f1 = checkForm(request.GET)   #  初始化一个表单验证对象,验证get方式提交的数据
    if f1.is_valid():   #  判断数据是否符合验证
        print(f1.cleaned_data)    #   打印合格的数据
    else:
        print(f1.errors)      #  #  打印错误信息

前端的页面:

def home(request):
    obj = checkForm()    #  通过checkForm生成一个表单
    return render(request, "index.html", locals())


---------------------------------------------------
<body>
    <form method="get" action=""> 
        {{obj.name}}
        {{obj.age}}
    </form>
</body>

对于form组件也可传入初始化值

两种传值的方式:1、通过initial参数。2、通过data参数

form = CheckForm(data={"title": obj.title})

这种方式传递的参数,会先进行form验证然后显示在页面上,如果有错,在页面上一并显示错误信息
只要页面上要显示错误信息就会进行验证

form = CheckForm(initial={"title": obj.title})

这种方式不会进行form的验证,直接在页面上进行显示

三、各字段的详细含义

CharField() 字段下的属性。  返回的类型是字符串类型。

name = field.CharField(
    max_length=8,     #  定义最大长度为8  
    min_length=2,     #  定义最小长度为2 
    requried=True,    #  是否为必填项
    disable=True,     #  定义是否可以编辑 
    localize=True,    #  定义是否支持本地化 
    error_message={"required":"请填写该选项"},   #  自定义错误信息,格式:{"属性名":"提示信息"}
    initial="请填写",  #  第一种设置默认值的方式
    label="姓名",      #   设置标签名,需要前端调用。    
    help_text="填写汉字",   # 帮助信息,需要前端调用。
    validators="",  # 用来放正则表达式进行对字符串的验证。
    show_hidden_initial=True,   #  创建一个默认的隐藏框在当前框的旁边用来比较值。
    label_suffix=":"   #  显示label 内容后缀。
)

一些属性的前端调用:

label属性:

{{obj.name.label}}     # 先调用字段再调用其属性

help_text属性:

{{obj.name.help_text}} 

error_messages 属性:

{{obj.errors.name.0}}   #  因为有可能有多个错误,所以就显示一个

前端一句话显示所有内容:

{{obj.as_p}}   所有内容展示在P标签内 

还有其他的方式  {{obj.as_ul}} 、{{obj.as_table}   但是不推荐这种方式

IntegerForm() 字段的属性。  返回的是整型。

因为IntegerForm 和 CharField 都是继承同一个父类form类,所以有一些相同的参数。下面介绍一些不同的参数:

age = field.IntegerField(
    max_value=99,   #  定义最大值 
    min_value=10    #  定义最小值
)

DecimalField()字段的属性。

salary = field.decimalField(
    max_digitals=5,    #  定义最大的位数。 
    decimal_place=2    #  定义小数点的位数。
}

FileField() 字段的属性。 

text = filed.FileField(allow_empty_file="True"  #  是否允许上传空文件)

ChoiceField()字段。  下拉框

classes = filed.ChoiceField(
    choices = [(1,"一班"),(2,"二班"),(3,"三班")],   # choices是数据源,后面跟一个列表,1代表value的值, "一班"代表文本内容。
    initial = 1 # 设置初始值
)

MultipleChoiceField()。 多选框。

city = field.MultipleChoiceField(
    choices=[(1,"xxx"),(2,"ooo")],
    initial = [1,2]   #  默认参数   
)

TypedChoiceField()。  和ChoiceField() 一样,多了一个可以处理数据的参数。

city = fields.TypedChoiceField(
        coerce=lambda x:int(x),   #  coerce 对类型的处理,这里可以自定义,不进行处理拿到的是字符
        choices=[(1,"村长"),(2,"Alex"),(3,"元昊")],
        initial=2  # 默认选中value为2的
    )

四、form的内置插件

需要设置widgets的参数,每个字段都有widget这个参数。我们先导入

from django.forms import widgets

widgets的使用:

# 创建一个下拉菜单
name = field.CharField( widget=widgets.Select(choices=[(1,"A"),(2,"B"),(3,"C")]))   # choices 是数据源

#  创建多选菜单

name = MultipleChiceField( widget=widgets.SelectMultiple(choices=[(1,"A"),(2,"B"),(3,"C")]) )

# 单选框
name = field.CharField(widget=widgets.RadioSelect(choices=[(1,"A"),(2,"B"),(3,"C")]))

# 复选框
name=field.CharField(widget=widgets.CheckboxSelectMultiple(choices=[(1,"A"),(2,"B"),(3,"C")]))

对于django帮我们自动创建好的HTML如何添加class或者其他属性呢:

name = field.CharField(widget=widgets.TextInput(attrs={"class":"active"}))  #  通过attr来添加class

特殊字段数据实时更新的问题:

由于类的属性在一开始加载时就分配空间, 当数据库有数据更新时,就无法获取到

class Love(forms.Form):
    price = fields.IntegerField()
    user_id = fields.IntegerField(widget=widgets.Select(Teacher.objects.all().values_List("id","name")))  # 这里仅在加载时执行查询

第一种解决方案(推荐):由于每次创建表单时,都会调用此类,所以在__init__()方法内执行。

class Love(forms.Form):
    price = fields.IntegerField()
    user_id = fields.IntegerField(widget=widgets.Select()) 

    def __init__(self):
        super().__init__()
        self.fields["user_id"].widget=widgets.Select(choices=Author.objects.values_list("id", "name"))    # 这里要用values_list

super方法会把自己的类属性都复制到self.fields下,所以super().__init__()必须方法到最前面,通过对self.fields进行值的修改。

第二种解决方案:

class Love(forms.Form):
    price = fields.IntegerField()
    user_id2 = ModelChoiceField(queryset=Author.objects.all())  #  ModelChoiceField()字段进行更新,queryset为数据库查询语句

然而这个方法无法打印属性值,所以需要结合__str__()方法进行打印

def __str__(self):
    return self.name

总结:在插件中,数据源(choices)都是写在插件里。

五、form组件的扩展(hook)

在源码中有三处可以进行扩展的钩子

def full_clean(self):       
    # 对单个字段进行验证
     self._clean_fields()   
    # 对整体进行验证
     self._clean_form()
    # 一个备用的钩子,一般不用,此处也是看了扩展的地方
     self._post_clean()

_clean_fields() :

关键代码和扩展的关键:

for name, field in self.fields.items():
            if field.disabled:
                value = self.get_initial_for_field(field, name)
            else:
                value = field.widget.value_from_datadict(self.data, self.files, self.add_prefix(name))
            try:
                if isinstance(field, FileField):
                    initial = self.get_initial_for_field(field, name)
                    value = field.clean(value, initial)
                else:
                    value = field.clean(value)
                self.cleaned_data[name] = value
                if hasattr(self, 'clean_%s' % name):    #  通过反射的方式进行查找以clean_开头的函数
                    value = getattr(self, 'clean_%s' % name)()  # 执行该方法并获取返回值
                    self.cleaned_data[name] = value   # 重新赋值
            except ValidationError as e:
                self.add_error(name, e)

所以可以在这里对各个字段单独进行处理。

from django.core.exceptions import NON_FIELD_ERRORS,ValidationError

class checkForm(forms.Form):
    name=field.CharField(max_length=8,min_length=2,required=True)
    age=field.IntegerField()
    city=filed.ChoiceField(widget=widgets.Select(choices=[(1,"A"),(2,"B"),(3,"C")])) 


    def clean_name(self):   #  对name字段进行验证
        v = self.cleaned_data["name"]
        if Author.objects.filter(name=v).count():  #  可以在这里抛出异常
            raise ValidationError("用户已存在","valid")
        return v

clean(): 在这里进行整体的验证

    def _clean_form(self):
        try:
            cleaned_data = self.clean()  # 扩展点,可以自定义clean函数
        except ValidationError as e:
            self.add_error(None, e)
        else:
            if cleaned_data is not None:
                self.cleaned_data = cleaned_data

可以这样做:

    def clean(self):
        user = self.cleaned_data["name"]
        if user == "asd":
            raise ValidationError("error")
        return self.cleaned_data

_post_clean():

这里可以自定义验证,由于没有可提供参考的异常,所以一般不在这里进行异常处理。

六、Django的序列化

对于Django的Queryset进行查询

from django.core import serializers  #  适用queryset的类型数据【obj,obj,obj】
import json

def te(request):
    response = {}
    response["mes"] = serializers.serialize("json",Author.objects.all())  # 参数为:格式,数据 
    print(json.dumps(response))   #  然后在dumps,对数据序列化了两次,前端反序列化两次
    return HttpResponse("ok")

对于values和values_list的查询结果:

import json
def te(request):
    response = {}
    # 只需要进行list()格式转换就好
    response["mes"] = list(Author.objects.all().values("name", "id"))
    #  response["mes"] = list(Author.objects.all().values_list("name", "id")) 
    print(json.dumps(response)) 
    return HttpResponse("ok")

对于平常的返回值,也可以直接返回一个json对象

from django.http import JsonResponse

def index(request):
    # JsonResponse()等价于HttpResponse+json.dumps
    return JsonResponse({"k1":"v1"})  返回值必须是一个字典

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值