Django-Form

简单操作步骤

1.创建UserForm类,继承forms.Form

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

2.views中引入UserForm

3.在前端创建与Form对应的表单

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

4.编写后台代码

def edit_user(request,nid):
    if request.method == "GET":
        data = models.UserInfo.objects.filter(id=nid).first()
        # 这一步必须,创建Form对象,返回给前端
        obj = UserForm({'username':data.username,'email':data.email})
        return render(request,'edit_user.html',{'obj':obj,'nid':nid})
    else:
        # 接受表单数据,生成UserForm对象
        obj = UserForm(request.POST)
        if obj.is_valid():
            # 如果验证成功,clean_data就是表单数据的字典形式
            models.UserInfo.objects.filter(id=nid).update(**obj.cleaned_data)
            return redirect('/users/')
        else:
            return render(request,'edit_user.html',{'obj':obj,'nid':nid})


前端快速生成

  • {{ obj_as_p }}
  • {{ obj_as_li }}
  • {{ obj_as_table }}

Form常用字段

  • Field
    - 字段
        ChoiceField *****  下拉
        MultipleChoiceField  下拉,多选
        CharField
        IntegerField
        DecimalField  小数
        DateField
        DateTimeField
        EmailField
        GenericIPAddressField  IP
        FileField 上传文件

Field本质上是一个widgest插件和一个正则表达式

forms.widgests 定制生成的HTML插件

  • 自定义input框中的属性
    widget = widgets.TextInput(attrs={'class':'c1'}), # 定制HTML插件 
  • select下拉框
    widget=widgets.Select(choices=[(1,'刚娘'),(2,'铁娘'),(3,'钢弹')])  

常用插件

http://www.cnblogs.com/haiyan123/p/7795771.html

Form实时更新

  • 方法一:给自定义Form加上__int__方法,让他每次实例化的时候都重新查询,并且继承父类的__init__方法(推荐)
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})
  • 方法二:利用modelField(不推荐,无法自定制)
        from django.forms.models import ModelChoiceField
        from django.forms.models import ModelChoiceField
        class LoveForm(forms.Form):
            price = fields.IntegerField()

            user_id2 = ModelChoiceField(
                queryset=models.UserInfo.objects.all(),
                to_field_name='id'
            )
        
        注意:依赖models中的str方法

Form自定义验证器

  • 根据正则表达式验证
1.简单扩展
        利用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': '...'})
                    
  • 基于源码流程扩展
  2.基于源码流程
        a. 单字段
            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']
                    
                 
        b. 整体错误验证
            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
                    
                    
        PS: _post_clean
                

注:重写clean方法是对form整体的进行验证(是为了了出来多个字段连个唯一的场景),他在字段验证之后执行,字段验证的错误信息的key为字段名称,整体验证的错误信息的key为__all__,可以使用obj.error.__all__点出来value

源码:

  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):
        value = getattr(self, 'clean_%s' % name)()
        self.cleaned_data[name] = value
    except ValidationError as e:
    self.add_error(name, e)

form的序列化

  • 如果是QuerySet对象数组(如all、filter拿到的等),先使用serialize将对象序列化为字符串添加进字典,再使用json.dumps将字典序列化为json字符串,然后再前端使用JSON.parse方法将该字符串序列化为JSON对象
from django.core import serializers
 
ret = models.BookType.objects.all()
 
data = serializers.serialize("json", ret)

result['data'] = data

json.dumps(result)
  • 如果对象是QuerySet对象,但里面是字典或者元组这样的python基本类型(如values values_list),只需要使用list()将其转换为python list基本数据类型即可
    ,然后再使用json.dumps进行转换,且前端不需要parse
import json
 
#ret = models.BookType.objects.all().values('caption')
ret = models.BookType.objects.all().values_list('caption')
 
ret=list(ret)
 
result = json.dumps(ret)

重点:python json.dumps()只能处理基本数据类型

Form 上传文件

注意:request.POST 中存放的参数
request.FILES 中存放的文件

  • 自己实现上传
def upload_file(request):
    if request.method == 'GET':
        return render(request, 'form/upload.html')
    else:
        file = request.FILES.get('img')
        filename = file.name
        f = open(filename,"wb")
        for line in file.chunks():
            f.write(line)
        f.close()
        return HttpResponse("提交成功")
  • 基于Form的上传
from django import forms
from django.forms import fields
class UploadForm(forms.Form):
    user = fields.CharField()
    img = fields.FileField()
def upload(request):
    if request.method == 'GET':
        return render(request,'upload.html')
    else:
         obj = UploadForm(request.POST,request.FILES)
        if obj.is_valid():
            user = obj.cleaned_data['user']
            img = obj.cleaned_data['img']
        <!--user = request.POST.get('user')-->
        <!--img  = request.FILES.get('img')-->
        # img是对象(文件大小,文件名称,文件内容。。。)
        print(img.name)
        print(img.size)
        f = open(img.name,'wb')
        for line in img.chunks():
            f.write(line)
        f.close()
        return HttpResponse('...')

你可能感兴趣的:(django)