• 西游之路——python全栈——通用模块(pager、check_code、form验证)


    1、验证码

     1 import random
     2 from PIL import Image, ImageDraw, ImageFont, ImageFilter
     3 
     4 _letter_cases = "abcdefghjkmnpqrstuvwxy"  # 小写字母,去除可能干扰的i,l,o,z
     5 _upper_cases = _letter_cases.upper()  # 大写字母
     6 _numbers = ''.join(map(str, range(3, 10)))  # 数字
     7 init_chars = ''.join((_letter_cases, _upper_cases, _numbers))
     8 
     9 
    10 def create_validate_code(size=(120, 30),
    11                          chars=init_chars,
    12                          img_type="GIF",
    13                          mode="RGB",
    14                          bg_color=(238, 99, 99),
    15                          fg_color=(0, 0, 255),
    16                          font_size=18,
    17                          font_type="Monaco.ttf",
    18                          length=4,
    19                          draw_lines=True,
    20                          n_line=(1, 2),
    21                          draw_points=True,
    22                          point_chance=2):
    23     """
    24     @todo: 生成验证码图片
    25     @param size: 图片的大小,格式(宽,高),默认为(120, 30)
    26     @param chars: 允许的字符集合,格式字符串
    27     @param img_type: 图片保存的格式,默认为GIF,可选的为GIF,JPEG,TIFF,PNG
    28     @param mode: 图片模式,默认为RGB
    29     @param bg_color: 背景颜色,默认为白色
    30     @param fg_color: 前景色,验证码字符颜色,默认为蓝色#0000FF
    31     @param font_size: 验证码字体大小
    32     @param font_type: 验证码字体,默认为 ae_AlArabiya.ttf
    33     @param length: 验证码字符个数
    34     @param draw_lines: 是否划干扰线
    35     @param n_lines: 干扰线的条数范围,格式元组,默认为(1, 2),只有draw_lines为True时有效
    36     @param draw_points: 是否画干扰点
    37     @param point_chance: 干扰点出现的概率,大小范围[0, 100]
    38     @return: [0]: PIL Image实例
    39     @return: [1]: 验证码图片中的字符串
    40     """
    41     width, height = size  # 宽高
    42     # 创建图形
    43     img = Image.new(mode, size, bg_color)
    44     draw = ImageDraw.Draw(img)  # 创建画笔
    45 
    46     def get_chars():
    47         """生成给定长度的字符串,返回列表格式"""
    48         return random.sample(chars, length)
    49 
    50     def create_lines():
    51         """绘制干扰线"""
    52         line_num = random.randint(*n_line)  # 干扰线条数
    53         for i in range(line_num):
    54             # 起始点
    55             begin = (random.randint(0, size[0]), random.randint(0, size[1]))
    56             # 结束点
    57             end = (random.randint(0, size[0]), random.randint(0, size[1]))
    58             draw.line([begin, end], fill=(0, 0, 0))
    59 
    60     def create_points():
    61         """绘制干扰点"""
    62         chance = min(100, max(0, int(point_chance)))  # 大小限制在[0, 100]
    63         for w in range(width):
    64             for h in range(height):
    65                 tmp = random.randint(0, 100)
    66                 if tmp > 100 - chance:
    67                     draw.point((w, h), fill=(0, 0, 0))
    68 
    69     def create_strs():
    70         """绘制验证码字符"""
    71         c_chars = get_chars()
    72         strs = ' %s ' % ' '.join(c_chars)  # 每个字符前后以空格隔开
    73         font = ImageFont.truetype(font_type, font_size)
    74         font_width, font_height = font.getsize(strs)
    75 
    76         draw.text(((width - font_width) / 3, (height - font_height) / 3),
    77                   strs, font=font, fill=fg_color)
    78 
    79         return ''.join(c_chars)
    80 
    81     if draw_lines:
    82         create_lines()
    83     if draw_points:
    84         create_points()
    85     strs = create_strs()
    86     # 图形扭曲参数
    87     params = [1 - float(random.randint(1, 2)) / 100,
    88               0,
    89               0,
    90               0,
    91               1 - float(random.randint(1, 10)) / 100,
    92               float(random.randint(1, 2)) / 500,
    93               0.001,
    94               float(random.randint(1, 2)) / 500
    95               ]
    96     img = img.transform(size, Image.PERSPECTIVE, params)  # 创建扭曲
    97     img = img.filter(ImageFilter.EDGE_ENHANCE_MORE)  # 滤镜,边界加强(阈值更大)
    98     return img, strs
    check_code.py

    需要配合 MONACO.TTF 字体使用

    2、分页

     1 class Pagination(object):
     2     def __init__(self,totalCount,currentPage,CurentUrl,perPageItemNum=3,maxPageNum=3,):
     3         # 所有数据总个数
     4         self.total_count = int(totalCount)
     5         # 当前页
     6         try:
     7             v = int(currentPage)
     8             if v <= 0:
     9                 v = 1
    10             self.current_page = v
    11 
    12         except Exception as e:
    13             self.current_page = 1
    14         # 每页显示行数
    15         self.per_page_item_num = int(perPageItemNum)
    16         # 最多页面数
    17         self.max_page_num = int(maxPageNum)
    18         self.current_url = CurentUrl
    19 
    20     def start(self):
    21         return (self.current_page - 1)*self.per_page_item_num
    22 
    23     def end(self):
    24         return self.current_page*self.per_page_item_num
    25 
    26     @property
    27     def num_pages(self):
    28         a,b = divmod(self.total_count,self.per_page_item_num)
    29         if b == 0:
    30             return a
    31         return a+1
    32 
    33     @property
    34     def pager_num_range(self):
    35         # 当前页
    36         # self.current_page
    37         # 最多显示页码数 7
    38         # self.per_page_num
    39         # 总页数
    40         # self.num_pages
    41         # 判断最小极值
    42         if self.max_page_num > self.num_pages:
    43             # 根据当前页动态生成,设置页面显示数
    44             return range(1, self.num_pages + 1)
    45         # 总页数特别多时
    46         part = int(self.max_page_num/2)
    47 
    48         if part >= self.current_page:
    49             return range(1, self.max_page_num + 1)
    50 
    51         # 判断最大极值
    52         if (self.current_page + part) >= self.num_pages:
    53             return range(self.num_pages - self.max_page_num + 1, self.num_pages + 1)
    54 
    55         return range(self.current_page - part, self.current_page + part +1)
    56 
    57     def page_str(self):
    58         page_list = []
    59 
    60         if self.current_page ==1:
    61             prev = "<li><a href='#'>上一页</a></li>"
    62         else:
    63             prev = "<li><a href='%s?p=%s'>上一页</a></li>" %(self.current_url,self.current_page-1)
    64         page_list.append(prev)
    65 
    66         first = "<li><a href='%s?p=1'>首页</a></li>" % self.current_url
    67         page_list.append(first)
    68 
    69         for i in self.pager_num_range:
    70             if self.current_page == i:
    71                 tem = "<li class='active'><a href='%s?p=%s'>%s</a></li>" % (self.current_url, i,i)
    72             else:
    73                 tem = "<li><a href='%s?p=%s'>%s</a></li>" % (self.current_url, i, i)
    74             page_list.append(tem)
    75 
    76         last = "<li><a href='%s?p=%s'>尾页</a></li>" % (self.current_url, self.num_pages)
    77         page_list.append(last)
    78 
    79         if self.current_page == self.num_pages:
    80             nex = "<li><a href='#'>下一页</a>"
    81         else:
    82             nex = "<li><a href='%s?p=%s'>下一页</a></li>" % (self.current_url, self.current_page + 1)
    83         page_list.append(nex)
    84 
    85         return ''.join(page_list)
    pager.py

    使用时需要传入三个参数

      - 信息总数

      - 当前页

      - 当前url

    1 obj_list = Pagination(article_list.count(), current_page, current_url)
    2     data_list = article_list[obj_list.start():obj_list.end()]
    视图函数中代码

    3、form验证

      1 from django import forms
      2 from django.forms import fields,widgets
      3 from repository import models
      4 from django.core.exceptions import ValidationError
      5 
      6 class RegisterForm(forms.Form):
      7     username = fields.CharField(
      8         label='用户名',
      9         required=True,
     10         max_length=32,
     11         initial='请输入用户名',
     12         error_messages={
     13             'required': '用户名不能为空',
     14             'min_length': '用户名过短',
     15             'invalid': '格式错误',
     16         }
     17     )
     18     password = fields.CharField(
     19         label='密码',
     20         required=True,
     21         max_length=32,
     22         min_length=6,
     23         error_messages={
     24             'required': '密码不能为空',
     25             'min_length': '密码长度太短',
     26             'invalid': '格式有误',
     27         }
     28     )
     29     # fields.RegexField()   自定义正则
     30     confirm_pwd = fields.CharField(
     31         label='确认密码',
     32         required=True,
     33         max_length=32,
     34         min_length=6,
     35         error_messages={
     36             'required': '密码不能为空',
     37             'min_length': '密码长度太短',
     38             'invalid': '格式有误',
     39         }
     40     )
     41     email = fields.EmailField(
     42         widget=widgets.EmailInput(attrs={"class":"form-control","placeholder": "输入邮箱"}),
     43         label='邮箱',
     44         required=True,
     45         error_messages={
     46             'required': '不能为空',
     47         }
     48     )
     49     # 注意使用cleaned_data.get('username')取值
     50     def clean_username(self):
     51         ret = models.User.objects.filter(username=self.cleaned_data.get('username'))
     52         if not ret:
     53             return self.cleaned_data.get('username')
     54         else:
     55             raise ValidationError('用户名已存在')
     56 
     57     def clean_password(self):
     58         pwd = self.cleaned_data.get('password')
     59         if not pwd.isdigit():
     60             return self.cleaned_data.get('password')
     61         else:
     62             raise ValidationError('不能全是数字')
     63 
     64     # 验证前后密码是否一致
     65     def clean(self):
     66         password = self.cleaned_data.get('password')
     67         confirm_pwd = self.cleaned_data.get('confirm_pwd')
     68         if confirm_pwd == password:
     69             return self.cleaned_data
     70         else:
     71             raise ValidationError('密码输入不一致')
     72 
     73 class LoginForm(forms.Form):
     74     username = fields.CharField(
     75         label='用户名',
     76         required=True,
     77         max_length=32,
     78         initial='请输入用户名',
     79         error_messages={
     80             'required': '用户名不能为空',
     81         }
     82     )
     83     password = fields.CharField(
     84         label='密码',
     85         required=True,
     86         max_length=32,
     87         min_length=6,
     88         error_messages={
     89             'required': '密码不能为空',
     90         }
     91     )
     92     def clean(self):
     93         user_list = models.User.objects.all().values_list('username','password')
     94         user_list = list(user_list)
     95         login_list = (self.cleaned_data.get('username'),self.cleaned_data.get('password'))
     96         if login_list in user_list:
     97             return self.cleaned_data
     98         else:
     99             raise ValidationError('用户名或密码错误')
    100 
    101 class ArticleForm(forms.Form):
    102     title = fields.CharField(
    103         label='标题',
    104         widget=widgets.TextInput(attrs={'class':'form-control', 'placeholder':'标题5-32个字符'}),
    105         required=True,
    106         min_length=5,
    107         max_length=32,
    108         error_messages={
    109             'required':'不能为空',
    110             'min_length':'标题最少为5个字节',
    111             'max_length':'标题最少为32个字节',
    112         }
    113     )
    114     summary = fields.CharField(
    115         label='简介',
    116         required=True,
    117         widget=widgets.Textarea(attrs={'class':'form-control', 'placeholder':'简介10-64个字符'}),
    118         max_length=32,
    119         min_length=10,
    120         error_messages={
    121             'required':'不能为空',
    122             'min_length':'简介最少为10个字节',
    123             'max_length':'简介最多为64个字节',
    124         }
    125     )
    126     detail = fields.CharField(
    127         label='内容',
    128         required=True,
    129         widget=widgets.Textarea(attrs={'id':'detail','class': 'kind-content', 'placeholder': '简介32-256个字符'}),
    130         max_length=256,
    131         min_length=32,
    132         error_messages={
    133             'required': '不能为空',
    134             'min_length': '简介最少为32个字节',
    135             'max_length': '简介最少为256个字节',
    136         }
    137     )
    138     user_choice = models.User.objects.all().values_list('id','username')
    139     user = fields.IntegerField(
    140         label='作者',
    141         widget=widgets.Select(choices=user_choice, attrs={'class':'form-control'})
    142     )
    143     blog_choice = models.Blog.objects.all().values_list('id','title')
    144     blog = fields.IntegerField(
    145         label='博客',
    146         widget=widgets.Select(choices=blog_choice, attrs={'class':'form-control'})
    147     )
    148     tags_choice = models.Tags.objects.all().values_list('id', 'caption')
    149     tags = fields.IntegerField(
    150         label='标签',
    151         widget=widgets.Select(choices=tags_choice, attrs={'class':'form-control'})
    152     )
    153     category_choice = models.Category.objects.all().values_list('id','caption')
    154     category = fields.IntegerField(
    155         label='分类',
    156         widget=widgets.Select(choices=category_choice, attrs={'class':'form-control'})
    157     )
    158 
    159     def clean(self):
    160         self.cleaned_data['user_id'] = self.cleaned_data.get('user')
    161         self.cleaned_data['tags_id'] = self.cleaned_data.get('tags')
    162         self.cleaned_data['blog_id'] = self.cleaned_data.get('blog')
    163         self.cleaned_data['category_id'] = self.cleaned_data.get('category')
    164         del self.cleaned_data['user']
    165         del self.cleaned_data['tags']
    166         del self.cleaned_data['blog']
    167         del self.cleaned_data['category']
    168         return self.cleaned_data
    169 
    170 class TroubleForm(forms.Form):
    171     title = fields.CharField(
    172         label='标题',
    173         required=True,
    174         widget=widgets.TextInput(attrs={'class':'form-control', 'placeholder':'输入标题5-32个字符'}),
    175         max_length=32,
    176         min_length=5,
    177         error_messages={
    178             'required':'标题不能为空',
    179             'min_length':'标题最少为5个字节',
    180             'invalid':'格式错误',
    181         }
    182     )
    183     detail = fields.CharField(
    184         label='内容',
    185         required=True,
    186         widget=widgets.Textarea(attrs={'id':'detail','class':'kind-content', 'placeholder':'输入内容5-256个字符'}),
    187         max_length=256,
    188         min_length=5,
    189         error_messages={
    190             'required': '内容不能为空',
    191             'min_length': '内容最少为5个字节',
    192             'invalid': '格式错误',
    193         }
    194     )
    注册、登录、编辑、添加

    有关form组件详情:稍后更新

     

  • 相关阅读:
    metal的gpu query
    体积雾 global fog unity 及改进
    hdr rt format对颜色的影响
    unity deferred lighting
    unity linear space时 photoshop blend的正确设置
    unity linear work flow
    一些数据 bandwidth之类
    deferred rendering with msaa
    unity 显示mipmaplevel
    【转】在C#中使用SendMessage
  • 原文地址:https://www.cnblogs.com/Lujun1028/p/9737857.html
Copyright © 2020-2023  润新知