博客论坛

此文专门记录一些用到的新知识。

一.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'))

  

原文地址:https://www.cnblogs.com/mitsui/p/7202332.html