django ModeForm:附示例
咱先内容回顾
Model - 数据库操作 - 验证 class A(MOdel): user = email = pwd =
Form - class LoginForm(Form): email = fields.EmailField() user = pwd =
在form中做验证的时候,它内部做了如下几步操作
is_valid --> 每一个字段进行正则(字段内置正则)+clean_字段 -> clean(__all__) --> _post_clean
ModeForm组件
ModelForm a. class Meta: model, # 对应Model的 fields=None, # 字段 exclude=None, # 排除字段 labels=None, # 提示信息 help_texts=None, # 帮助提示信息 widgets=None, # 自定义插件 error_messages=None, # 自定义错误信息(整体错误信息from django.core.exceptions import NON_FIELD_ERRORS) field_classes=None # 自定义字段类 (也可以自定义字段) localized_fields=('birth_date',) # 本地化,如:根据不同时区显示数据 如: 数据库中 2016-12-27 04:10:57 setting中的配置 TIME_ZONE = 'Asia/Shanghai' USE_TZ = True 则显示: 2016-12-27 12:10:57 b. 验证执行过程 is_valid -> full_clean -> 钩子 -> 整体错误 c. 字典字段验证 def clean_字段名(self): # 可以抛出异常 # from django.core.exceptions import ValidationError return "新值" d. 用于验证 model_form_obj = XXOOModelForm() model_form_obj.is_valid() model_form_obj.errors.as_json() model_form_obj.clean() model_form_obj.cleaned_data e. 用于创建 model_form_obj = XXOOModelForm(request.POST) #### 页面显示,并提交 ##### # 默认保存多对多 obj = form.save(commit=True) # 不做任何操作,内部定义 save_m2m(用于保存多对多) obj = form.save(commit=False) obj.save() # 保存单表信息 obj.save_m2m() # 保存关联多对多信息 f. 用于更新和初始化 obj = model.tb.objects.get(id=1) model_form_obj = XXOOModelForm(request.POST,instance=obj) ... PS: 单纯初始化 model_form_obj = XXOOModelForm(initial={...})
归纳一下
Model + Form => 验证 + 数据库操作 - class LoginModelForm(from.ModelForm): class Meata: model= model.UserInfo fileds = ‘__all__’ 利用model.A中的字段
From验证
class UserInfoModelForm(forms.ModelForm): ---》form --》BaseForm(is_valid方法) 1. 生成HTML标签:class Meta: ... 2. mf = xxxModelForm(instance=ModelObj) 3. 额外的标签, is_rmb = Ffields.CharField(widget=Fwidgets.CheckboxInput()) 4. 各种验证 is_valid() -> 各种钩子... 5. mf.save() # 或 instance = mf.save(False) instance.save() mf.save_m2m()
ModelForm:来进行验证+数据库操作
from django import forms from app01 import models #如果在form中使用 obj.is_vaild() 就是验证功能 class ArticleFrom(forms.ModelForm): #拿不到固定字段的时候,用这个方法 def __new__(cls, *args, **kwargs): #重写了new方法,你必须去继承父类的new方法,不然就会导致整个form的失效 for field_name in cls.base_fields: #通过cls拿到它的base_fields,base_fields是在里面写死了,通过它可以拿到里面所有的字段 field = cls.base_fields[field_name] # 然后拿到所有的字段, 就可以进去判断类型 attr_dic = {'class':'form-control'} # if field_name == "body": # attr_dic.update({"id":"article_editor"}) field.widget.attrs.update(attr_dic) #拿到并更新一个样式 return forms.ModelForm.__new__(cls) class Meta: model = models.Article fields = "__all__" exclude=('author','priority') #隐藏这2个值
views
#如果前端传入了文件,那后端就需要使用request.FILES 来解释 article_form = forms.ArticleFrom(data=request.POST,files=request.FILES,) if article_form.is_valid(): article_form.cleaned_data['author_id'] = request.user.id #在清除后的数据中添加 author,这个author是根据数据库中的字段来进行添加 #article_form.save() print('user',request.user.id) print('clean data',article_form.cleaned_data) tags = article_form.cleaned_data.pop("tags") return render(request,'new_article.html',{"form":article_form}) #### 如果你想让form生成的前端样式中有默认数据就需要传入instace if request.method == "GET": articles = models.Article.objects.filter(category_id=category_id) mf = forms.ArticleFrom(instace=articles ) #这样就有默认数据了
示例:
咱可以先自定义一个插件
from django.shortcuts import render,HttpResponse from app01 import models from django import forms from django.forms import fields as Ffields from django.forms import widgets as Fwidgets class UserInfoModelForm(forms.ModelForm): #自定义一个插件 is_rmb = Ffields.CharField(widget=Fwidgets.CheckboxInput()) #这个是标准的modeform格式! class Meta: ##modefrom里面用的字段就是mode里面的 model = models.UserInfo #去哪一个类里面获取字段 并可以增删改查 fields = '__all__' # fields = ['username','email'] #这样就只会显示2个了 # exclude = ['username'] #排除username,其他就都出来了 labels = { 'username': '用户名', 'email': '邮箱', } help_texts = { 'username': '...' } widgets = { 'username': Fwidgets.Textarea(attrs={'class': 'c1'}) } error_messages = { '__all__':{ }, 'email': { 'required': '邮箱不能为空', 'invalid': '邮箱格式错误..', } } field_classes = { # 'email': Ffields.URLField } # localized_fields=('ctime',) def clean_username(self): old = self.cleaned_data['username'] return old class UserInfoForm(forms.Form): username = Ffields.CharField(max_length=32) email = Ffields.EmailField() user_type = Ffields.ChoiceField( choices=models.UserType.objects.values_list('id','caption') ) def __init__(self, *args, **kwargs): super(UserInfoForm,self).__init__(*args, **kwargs) self.fields['user_type'].choices = models.UserType.objects.values_list('id','caption') def index(request): if request.method == "GET": obj = UserInfoModelForm() return render(request,'index.html',{'obj': obj}) elif request.method == "POST": obj = UserInfoModelForm(request.POST) if obj.is_valid(): # obj.save() instance = obj.save(False) instance.save() obj.save_m2m() #modefrom 跟form 这里提供的是一样的方法 # print(obj.is_valid()) # print(obj.cleaned_data) # print(obj.errors.as_json()) return render(request,'index.html',{'obj': obj}) def user_list(request): li = models.UserInfo.objects.all().select_related('user_type') return render(request,'user_list.html',{'li': li}) def user_edit(request, nid): # 获取当前id对象的用户信息 # 显示用户已经存在数据 if request.method == "GET": user_obj = models.UserInfo.objects.filter(id=nid).first() mf = UserInfoModelForm(instance=user_obj) ###如果需要点击一个编辑页面后 把默认值传递进来就需要 instance=这个对象 return render(request,'user_edit.html',{'mf': mf, 'nid': nid}) elif request.method == 'POST': ###如果要进行更新的话。需要告知哪个行,或者哪个字段进行更新。所以需要在传递instance, #这就表示你把数据提交过来。拿到你的数据是对哪个对象进行更新 #!!instance参数!! 。如果增加就不需要传递instance参数 user_obj = models.UserInfo.objects.filter(id=nid).first() mf = UserInfoModelForm(request.POST,instance=user_obj) if mf.is_valid(): ##可以做一些操作,例如通过验证了 报错session多长时间 mf.save() else: print(mf.errors.as_json()) return render(request,'user_edit.html',{'mf': mf, 'nid': nid}) def ajax(request): return render(request, 'ajax.html') def ajax_json(request): import time time.sleep(3) print(request.POST) ret = {'code': True , 'data': request.POST.get('username')} import json return HttpResponse(json.dumps(ret)) def upload(request): return render(request,'upload.html') def upload_file(request): username = request.POST.get('username') fafafa = request.FILES.get('fafafa') import os img_path = os.path.join('static/imgs/',fafafa.name) with open(img_path,'wb') as f: for item in fafafa.chunks(): f.write(item) ret = {'code': True , 'data': img_path} import json return HttpResponse(json.dumps(ret)) def kind(request): return render(request, 'kind.html') def upload_img(request): request.GET.get('dir') print(request.FILES.get('fafafa')) # 获取文件保存 import json dic = { 'error': 0, 'url': '/static/imgs/20130809170025.png', 'message': '错误了...' } return HttpResponse(json.dumps(dic)) import os import time import json def file_manager(request): """ 文件管理 :param request: :return: { moveup_dir_path: current_dir_path: current_url: file_list: [ { 'is_dir': True, 'has_file': True, 'filesize': 0, 'dir_path': '', 'is_photo': False, 'filetype': '', 'filename': xxx.png, 'datetime': time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(os.path.getctime(abs_item_path))) }, { 'is_dir': True, 'has_file': True, 'filesize': 0, 'dir_path': '', 'is_photo': False, 'filetype': '', 'filename': xxx.png, 'datetime': time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(os.path.getctime(abs_item_path))) } ] } """ dic = {} root_path = 'C:/Users/Administrator/PycharmProjects/day24/static/' static_root_path = '/static/' request_path = request.GET.get('path') if request_path: abs_current_dir_path = os.path.join(root_path, request_path) move_up_dir_path = os.path.dirname(request_path.rstrip('/')) dic['moveup_dir_path'] = move_up_dir_path + '/' if move_up_dir_path else move_up_dir_path else: abs_current_dir_path = root_path dic['moveup_dir_path'] = '' dic['current_dir_path'] = request_path dic['current_url'] = os.path.join(static_root_path, request_path) file_list = [] for item in os.listdir(abs_current_dir_path): abs_item_path = os.path.join(abs_current_dir_path, item) a, exts = os.path.splitext(item) is_dir = os.path.isdir(abs_item_path) if is_dir: temp = { 'is_dir': True, 'has_file': True, 'filesize': 0, 'dir_path': '', 'is_photo': False, 'filetype': '', 'filename': item, 'datetime': time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(os.path.getctime(abs_item_path))) } else: temp = { 'is_dir': False, 'has_file': False, 'filesize': os.stat(abs_item_path).st_size, 'dir_path': '', 'is_photo': True if exts.lower() in ['.jpg', '.png', '.jpeg'] else False, 'filetype': exts.lower().strip('.'), 'filename': item, 'datetime': time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(os.path.getctime(abs_item_path))) } file_list.append(temp) dic['file_list'] = file_list return HttpResponse(json.dumps(dic))
在来一个登陆页面的验证码代码
#!/usr/bin/env python # -*- coding:utf-8 -*- import random from PIL import Image, ImageDraw, ImageFont, ImageFilter _letter_cases = "abcdefghjkmnpqrstuvwxy" # 小写字母,去除可能干扰的i,l,o,z _upper_cases = _letter_cases.upper() # 大写字母 _numbers = ''.join(map(str, range(3, 10))) # 数字 init_chars = ''.join((_letter_cases, _upper_cases, _numbers)) def create_validate_code(size=(120, 30), chars=init_chars, img_type="GIF", mode="RGB", bg_color=(255, 255, 255), fg_color=(0, 0, 255), font_size=18, font_type="Monaco.ttf", length=4, draw_lines=True, n_line=(1, 2), draw_points=True, point_chance=2): """ @todo: 生成验证码图片 @param size: 图片的大小,格式(宽,高),默认为(120, 30) @param chars: 允许的字符集合,格式字符串 @param img_type: 图片保存的格式,默认为GIF,可选的为GIF,JPEG,TIFF,PNG @param mode: 图片模式,默认为RGB @param bg_color: 背景颜色,默认为白色 @param fg_color: 前景色,验证码字符颜色,默认为蓝色#0000FF @param font_size: 验证码字体大小 @param font_type: 验证码字体,默认为 ae_AlArabiya.ttf @param length: 验证码字符个数 @param draw_lines: 是否划干扰线 @param n_lines: 干扰线的条数范围,格式元组,默认为(1, 2),只有draw_lines为True时有效 @param draw_points: 是否画干扰点 @param point_chance: 干扰点出现的概率,大小范围[0, 100] @return: [0]: PIL Image实例 @return: [1]: 验证码图片中的字符串 """ width, height = size # 宽高 # 创建图形 img = Image.new(mode, size, bg_color) draw = ImageDraw.Draw(img) # 创建画笔 def get_chars(): """生成给定长度的字符串,返回列表格式""" return random.sample(chars, length) def create_lines(): """绘制干扰线""" line_num = random.randint(*n_line) # 干扰线条数 for i in range(line_num): # 起始点 begin = (random.randint(0, size[0]), random.randint(0, size[1])) # 结束点 end = (random.randint(0, size[0]), random.randint(0, size[1])) draw.line([begin, end], fill=(0, 0, 0)) def create_points(): """绘制干扰点""" chance = min(100, max(0, int(point_chance))) # 大小限制在[0, 100] for w in range(width): for h in range(height): tmp = random.randint(0, 100) if tmp > 100 - chance: draw.point((w, h), fill=(0, 0, 0)) def create_strs(): """绘制验证码字符""" c_chars = get_chars() strs = ' %s ' % ' '.join(c_chars) # 每个字符前后以空格隔开 font = ImageFont.truetype(font_type, font_size) font_width, font_height = font.getsize(strs) draw.text(((width - font_width) / 3, (height - font_height) / 3), strs, font=font, fill=fg_color) return ''.join(c_chars) if draw_lines: create_lines() if draw_points: create_points() strs = create_strs() # 图形扭曲参数 params = [1 - float(random.randint(1, 2)) / 100, 0, 0, 0, 1 - float(random.randint(1, 10)) / 100, float(random.randint(1, 2)) / 500, 0.001, float(random.randint(1, 2)) / 500 ] img = img.transform(size, Image.PERSPECTIVE, params) # 创建扭曲 img = img.filter(ImageFilter.EDGE_ENHANCE_MORE) # 滤镜,边界加强(阈值更大) return img, strs

浙公网安备 33010602011771号