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
需要配合 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)
使用时需要传入三个参数
- 信息总数
- 当前页
- 当前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组件详情:稍后更新