此文专门记录一些用到的新知识。
一.Form组件验证登录:
#Form表单定制验证码: code = fields.CharField(widget=widgets.TextInput( attrs={'class': "form-control", 'placeholder': '验证码'}), ) #将request一并传入,用来获取session,因此在使用Form组件时,实例化时要传request #如 obj = RegForm(request,request.POST) def __init__(self,request,*args,**kwargs): super().__init__(*args,**kwargs) self.request = request #自定义验证规则,验证用户输入的验证码是否正确 def clean_code(self): #取到已经写入session的验证码'code' session_code = self.request.session.get('code') #与取到的用户输入值进行匹配,判断是否正确 input_code = self.cleaned_data.get('code') if session_code == input_code: return input_code raise ValidationError('验证码错误') #验证码视图函数 from utils.random_check_code import rd_check_code from io import BytesIO from utils.FormInfo import LoginInfo,RegForm def check_code(request): #使用自定制的验证码生成函数,得到返回值为 img:验证码生成的图片,code:验证码生成的实际字符串 img, code = rd_check_code() #打开内存写入验证码图片,BytesIO可以写入二进制文件 stream = BytesIO() img.save(stream, 'png') #将生成的验证码字符串写入session便于Form组件的验证 request.session['code'] = code #getvalue()方法可以获取写入的数据,即此函数发送的是生成的图片 return HttpResponse(stream.getvalue()) #实际应用:注册用户为例 #后端代码: def reg(request): if request.method == 'GET': #即使GET时无需验证,但Form规定了要传一个request,所以这里也要传参 obj = RegForm(request) return render(request,'sign.html',{'obj':obj}) else: #传入request便于获取session验证 obj = RegForm(request,request.POST) if not obj.is_valid(): return render(request,'sign.html',{'obj':obj}) else: obj.cleaned_data.pop('pwd_again') models.UserInfo.objects.create(**obj.cleaned_data) return redirect('/login.html')
前端代码:
<div class="form-group" style="margin-top: 60px"> <label class="col-sm-2 control-label">验证码</label> <div class="col-sm-3"> {{ obj.code }} </div> <div class="col-sm-5"> <!-- 验证码图片写上/check_code/,Django urls里再配置好指向处理验证码的函数, 此时页面加载向check_code发请求,返回的就是生成好的图片达到生成验证码的效果 --> <img style=" 120px;height: 30px;" src="/check_code/" id="img-code"> </div> <span style="color: red"> {{ obj.errors.code.0 }}</span> </div>
验证码生成函数代码:
#需要安装PIL模块生成图片 from PIL import Image,ImageDraw,ImageFont,ImageFilter import random #font_file指向字体文件路径: def rd_check_code(width=120, height=30, char_length=5, font_file='kumo.ttf', font_size=28): code = [] img = Image.new(mode='RGB', size=(width, height), color=(255, 255, 255)) draw = ImageDraw.Draw(img, mode='RGB') def rndChar(): """ 生成随机字母 :return: """ return chr(random.randint(65, 90)) def rndColor(): """ 生成随机颜色 :return: """ return (random.randint(0, 255), random.randint(10, 255), random.randint(64, 255)) # 写文字 font = ImageFont.truetype(font_file, font_size) for i in range(char_length): char = rndChar() code.append(char) h = random.randint(0, 4) draw.text([i * width / char_length, h], char, font=font, fill=rndColor()) # 写干扰点 for i in range(10): draw.point([random.randint(0, width), random.randint(0, height)], fill=rndColor()) # 写干扰圆圈 for i in range(10): draw.point([random.randint(0, width), random.randint(0, height)], fill=rndColor()) x = random.randint(0, width) y = random.randint(0, height) draw.arc((x, y, x + 4, y + 4), 0, 90, fill=rndColor()) # 画干扰线 for i in range(3): x1 = random.randint(0, width) y1 = random.randint(0, height) x2 = random.randint(0, width) y2 = random.randint(0, height) draw.line((x1, y1, x2, y2), fill=rndColor()) img = img.filter(ImageFilter.EDGE_ENHANCE_MORE)
#返回值为图片以及验证码字符串 return img,''.join(code)
clean()方法是其它全部的验证规则执行完毕才会执行,通常可以用来对多个字段之间进行共同验证,比如验证2次输入密码是否一致。 def clean(self): p1 = self.cleaned_data.get('password') p2 = self.cleaned_data.get('password2') if p1 == p2: #clean方法return的不是字段 return None #同样的,添加错误是往None添加,在试图函数中通过obj.errors['__all__']取值, 而在模版中则通过obj.errors.non_field_errors取值,此为常规写法。 # self.add_error(None,ValidationError('密码不一致')) #当然,使用add_error函数可以往None里添加,自然也能往我们的字段中添加, 即key,value中key改为我们的字段名,即模版中相对应也可以obj.errors.字段名来取。 self.add_error("password2",ValidationError('密码不一致'))
二.models应用:
1.分组:
#分类函数 from django.db.models import Count,Min,Max,Sum #values里写以什么字段进行分组以及可以取到的字段,然后.annotate(别名=Count('聚合计算个数的字段,也可以直接写1')) cate_list = models.Article.objects.filter(blog__site=site).values('category__title','category__nid').annotate(c=Count('nid')) tags_list = models.Article.objects.filter(blog__site=site).values('tags__title','tags__nid').annotate(c=Count(1)) #时间查询需要涉及到时间的格式化,额外的东西所以这里用到extar #mysql查询 # data_time = models.Article.objects.extra(select={'c':'date_fomat(create_time,"%%Y-%%m")'}).values('c').annotate(ct=Count('nid')) #sqlite3查询 date_list = models.Article.objects.filter(blog__site=site).extra(select={'c':'strftime("%%Y-%%m",create_time)'}). values('c').annotate(ct=Count('nid'))