报障系统之博客主页及后台管理
个人博客:
url函数(路由系统):
"""baozhang URL Configuration The `urlpatterns` list routes URLs to views. For more information please see: https://docs.djangoproject.com/en/1.11/topics/http/urls/ Examples: Function views 1. Add an import: from my_app import views 2. Add a URL to urlpatterns: url(r\'^$\', views.home, name=\'home\') Class-based views 1. Add an import: from other_app.views import Home 2. Add a URL to urlpatterns: url(r\'^$\', Home.as_view(), name=\'home\') Including another URLconf 1. Import the include() function: from django.conf.urls import url, include 2. Add a URL to urlpatterns: url(r\'^blog/\', include(\'blog.urls\')) """ from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r\'^admin/\', admin.site.urls), url(r\'^all/(?P<type_id>\d+)/\', views.index), url(r\'^login/\', views.login), url(r\'^logout/\', views.logout), url(r\'^check_code/\', views.check_code), url(r\'^register/\', views.register),注册页面 url(r\'^(?P<site>\w+)/(?P<key>((tag)|(category)|(date)))/(?P<val>\w+-*\w*).html$\', views.home_filter),#筛选 url(r\'^(?P<site>\w+).html$\', views.home),#个人已开通博客主页 url(r\'^(?P<site>\w+)/p/(?P<nid>\w+).html$\', views.detail), # 文章详细 url(r\'^(?P<site>\w+)/(?P<nid>\d+).html$\', views.article),#评论 url(r\'^up.html$\', views.up),#点赞或踩 url(r\'^lizhi-(?P<article_type_id>\d+)-(?P<categpry_id>\d+)-(?P<tags_id>\d+).html$\', views.lizhi), url(r\'^upload/\', views.upload),#上传 # url(r\'^openblog/\', views.openblog), # url(r\'^(\w+)/\', views.blog), url(r\'^test/\', views.test), # url(r\'^(\w+)/$\', views.home), url(r\'^\', views.index),#个人主页 ]
报障系统主页
def index(request, *args, **kwargs): """ 个人主页 :param request: :param args: :param kwargs: :return: """ # print(request.path_info) # /all/1/ /all/2/ username = request.session.get(\'username\') obj = models.UserInfo.objects.filter(username=username).values(\'blog__site\').first() condition = {} type_id = int(kwargs.get(\'type_id\')) if kwargs.get(\'type_id\') else None # 如果kwargs.get(\'type_id\')有值时转成整型没有值等于None if type_id: condition[\'article_type_id\'] = type_id article_list = models.Article.objects.filter(**condition) # article_type_id = models.IntegerField(choices=type_choices, default=None) type_choice_list = models.Article.type_choices # 文章分类 user_list = models.UserInfo.objects.filter() return render( request, \'index.html\', { \'username\': username, \'obj\': obj, \'type_id\': type_id, \'type_choice_list\': type_choice_list, \'article_list\': article_list, } )
Class Form类
注册类:
from django.forms import Form from django.forms import fields from django.forms import widgets from django.core.exceptions import ValidationError from django.core.validators import RegexValidator from app01 import models class RegisterForm(Form): username = fields.CharField( required=True, widget=widgets.TextInput( attrs={\'class\':\'form-control\',\'placeholder\':\'用户名为6-10个字符\'} ), min_length=6, max_length=10, strip=True, error_messages={ \'required\': \'用户名不能为空\', \'min_length\':\'用户名至少为6个字符\', \'max_length\':\'用户名不超过10个字符\', }, ) password = fields.CharField( required=True, widget=widgets.PasswordInput( attrs={\'class\':\'form-control\',\'placeholder\':\'密码为8-12个字符\'} ), min_length=8, max_length=12, strip=True, validators=[ RegexValidator(r\'((?=.*\d))^.{8,12}$\',\'必须包含数字\'), RegexValidator(r\'((?=.*[a-zA-Z]))^.{8,12}\',\'必须包含字母\'), # RegexValidator(r\'((?=.*[^a-zA-Z0-9]))^.{8,12}\',\'必须包含特殊字符\'), # RegexValidator(r\'^.(\s){8,12}\',\'必须包含空格\'), ],#用于对密码的正则验证 error_messages={ \'required\': \'密码不能为空\', \'min_length\':\'密码不能少于8个字符\', \'max_length\':\'密码最多为12个字符!\', } ) password_again = fields.CharField( required=True, widget=widgets.PasswordInput( attrs={\'class\':\'form-control\',\'placeholder\':\'密码为8-12个字符\'} ), min_length=8, max_length=12, strip=True, error_messages={\'required\':\'请再次输入密码!\',} ) nickname = fields.CharField( required=True, widget=widgets.TextInput( attrs={\'class\':\'form-control\',\'placeholder\':\'请输入昵称\'} ) ) email = fields.EmailField( required=True, widget=widgets.TextInput(attrs={\'class\':\'form-control\',\'placeholder\':\'请输入邮箱\'}), # strip=True, # error_messages={\'required\':\'邮箱不能为空\',\'invalid\':\'请输入正确的邮箱格式\'}, ) avatar = fields.FileField(widget=widgets.FileInput(attrs={\'id\':\'imgFile\',\'class\':\'f1\'})) code = fields.CharField(widget=widgets.TextInput(attrs={\'class\':\'form-control\',\'placeholder\':\'请输入验证码\'})) def clean_username(self): #对于username扩展验证,查看是否存在 username = self.cleaned_data[\'username\'] users = models.UserInfo.objects.filter(username=username).count() if users:#如果用户名已存在 raise ValidationError(\'用户名已经存在!\') return username def clean_email(self): #对于email的扩展验证,查看是否存在 email = self.cleaned_data[\'email\'] email_count = models.UserInfo.objects.filter(email=email).count() if email_count: raise ValidationError(\'邮箱已经存在!\') return email # def _clean_password(self):#验证两次输入密码是否一致 # password1 = self.cleaned_data[\'password\'] # password2 = self.cleaned_data[\'password_again\'] # if password1 and password2: # if password1 != password2: # raise ValidationError(\'您两次输入的密码不一致\') def __init__(self,request,*args,**kwargs):#构造方法,传request参数 super(RegisterForm,self).__init__(*args,**kwargs)#完成原有form功能以外 self.request = request#再封装一个request def clean_code(self): input_code = self.cleaned_data[\'code\'] session_code = self.request.session.get(\'code\')#session取验证码 if input_code.upper() == session_code.upper():#验证相等时 return input_code# raise ValidationError(\'验证码错误\') def clean(self): # 验证两次输入密码是否一致 p1 = self.cleaned_data.get(\'password\') p2 = self.cleaned_data.get(\'password_again\') if p1 == p2: # return self.cleaned_data return None # else: # raise ValidationError(\'密码不一致\') self.add_error("password_again",ValidationError(\'密码不一致\')) # except ValidationError as e: # self.add_error(name, e) # def clean(self): # #基于form对象的验证,字段全部验证通过会调用clean函数验证 # self._clean_password()#调用函数 # p1 = self.cleaned_data[\'password\'] # p2 = self.cleaned_data[\'password_again\'] # return p2 # def clean_password(self): # p1 = self.cleaned_data[\'password\'] # p2 = self.cleaned_data[\'password_again\'] return p2
登录类:
class LoginForm(forms.Form): """用户登录form验证""" username = fields.CharField( required=True, widget=widgets.TextInput(attrs={\'class\': \'form-control\', \'placeholder\': \'请输入用户名\'}), min_length=6, max_length=10, strip=True, error_messages={\'required\': \'用户名不能为空\', } ) password = fields.CharField( required=True, widget=widgets.TextInput(attrs={\'class\': \'form-control\', \'placeholder\': \'请输入密码\'}), max_length=12, min_length=8, strip=True, error_messages={\'required\': \'密码不能为空\', } ) def clean(self): username = self.cleaned_data.get(\'username\') password = self.cleaned_data.get(\'password\') user_list = models.UserInfo.objects.filter(username=username).first() if username and password: if not user_list: raise ValidationError(\'用户名不存在,请重新输入\') elif password != user_list.password: raise ValidationError(\'密码错误\')
用户登录视图函数
# 用户登录 def login(request): # GET请求 """ 用户登录 :param request: :return: """ if request.method == "GET": obj = LoginForm() return render(request, \'login.html\', {\'obj\': obj}) else: # print(request.POST) # obj = LoginForm(request.POST) # errors = {} # print(obj.errors) # print(obj) # print(request.session) # if obj.is_valid(): input_code = request.POST.get(\'code\') # print(input_code) session_code = request.session.get(\'code\') if input_code.upper() == session_code.upper(): # 判断验证码是否正确 username = request.POST.get(\'username\') user_list = models.UserInfo.objects.filter(username=username).first() print(user_list) if user_list: password = request.POST.get(\'password\') if user_list.password == password: request.session[\'is_login\'] = \'true\' request.session[\'username\'] = user_list.username return redirect(\'/\') else: msg = \'密码错误\' obj = LoginForm(request.POST) return render(request, \'login.html\', {\'msg\': msg, \'obj\': obj}) else: msg = \'该账号不存在\' obj = LoginForm(request.POST) return render(request, \'login.html\', {\'msg\': msg, \'obj\': obj}) else: msg = \'验证码错误\' obj = LoginForm(request.POST) return render(request, \'login.html\', {\'msg\': msg, \'obj\': obj}) # if request.POST.get(\'auto_login\'): # request.session.get_expiry(60*60*24*24) # # request.session[\'is_login\'] = \'true\' # # request.session[\'username\'] = data.get(\'username\') # print(request.session[\'username\']) # print(\'123\') # return redirect(\'/\') # else: # errors[\'code\'] = \'请输入正确的验证码\' # return render(request,\'login.html\',{\'obj\':obj,\'errors\':errors}) # return render(request,\'login.html\',{\'obj\':obj})
退出登录:
def logout(request): """ 用户退出登录 :param request: :return: """ try: # 删除is_login对应的value值 del request.session[\'is_login\'] del request.session[\'username\'] except KeyError: pass return redirect(\'/login/\') #验证码
获取验证码:
#验证码 def check_code(request): """ #读取硬盘中的文件,在页面显示 # f = open(\'static/images/aa.png\',\'rb\') # data = f.read() # f.close() # return HttpResponse(data) #先写到本地,再读出到页面 # from PIL import Image # f = open(\'code.png\',\'wb\') # img = Image.new(mode=\'RGB\',size=(120,30),color=(255,255,255)) # img.save(f,\'png\') # f.close() # # f = open(\'code.png\',\'rb\') # data = f.read() # f.close() #内存开辟一块空间 from PIL import Image,ImageDraw,ImageFont from io import BytesIO f = BytesIO() img = Image.new(mode=\'RGB\',size=(120,30),color=(255,255,255))#图片对象 draw = ImageDraw.Draw(img,mode=\'RGB\')#画笔对象 #画点 draw.point([10,10],fill="red") draw.point([30,10],fill="red") #画线 draw.line((15,10,50,50),fill=\'red\') draw.line((45,20,100,100),fill=(0,255,0)) #画圆圈 draw.arc((0,0,30,30),0,360,fill="red") #写文本内容 # draw.text([0,0],\'python\',"red") # font = ImageFont.truetype("kumo.ttf",28) # draw.text([0,0],\'python\',(0,255,0),font=font) import random #生成随机数 # char_list = [] # for i in range(5): # char = chr(random.randint(65,90)) # char_list.append(char) # \'\'.join(char_list) # v = \'\'.join([chr(random.randint(65,90)) for i in range(5)]) char_list = [] for i in range(5): char = chr(random.randint(65,90)) char_list.append(char)#保存写的随机字符 font = ImageFont.truetype("kumo.ttf",28) draw.text([i*24,0],char,(random.randint(0,255),random.randint(0,255),random.randint(0,255)),font=font) # code = \'\'.join(char_list) img.save(f,\'png\') data = f.getvalue()#读取内存里的值 code = \'\'.join(char_list) print(request.session)#<django.contrib.sessions.backends.db.SessionStore object at 0x00000258DB88DC88> request.session[\'code\'] = code#保存在session里 """ from io import BytesIO from utils.random_check_code import rd_check_code stream = BytesIO() img, code = rd_check_code() img.save(stream, \'png\') # data = stream.getvalue() request.session[\'code\'] = code return HttpResponse(stream.getvalue())
用户注册时上传头像:
import os #用户上传图片 def upload(request): print(request.POST, request.FILES) file_obj = request.FILES.get(\'imgUrl\') #取文件时,需以FILES获取文件数据 file_path = os.path.join(\'static/img/\', file_obj.name) print(file_path) with open(file_path, \'wb\') as f: # 以wb方式写入到指定目录(bytes格式写入) # 写字节方式打开空文件,拼接文件路径 for trunk in file_obj.chunks(): # 写入到指定目录 f.write(trunk) return HttpResponse("/" + file_path)
用户注册:
def register(request): """ 用户注册 :param request: :return: """ if request.method == "GET": obj = RegisterForm(request) return render(request, \'register.html\', {\'obj\': obj}) else: # 验证码 obj = RegisterForm(request, request.POST, request.FILES) if obj.is_valid(): print(type(obj.cleaned_data)) dict = {} dict[\'username\'] = obj.cleaned_data[\'username\'] dict[\'password\'] = obj.cleaned_data[\'password\'] dict[\'nickname\'] = obj.cleaned_data[\'nickname\'] dict[\'email\'] = obj.cleaned_data[\'email\'] dict[\'avatar\'] = obj.cleaned_data[\'avatar\'] models.UserInfo.objects.create(**dict) return redirect(\'/\') else: # print(obj.errors[\'__all__\']) # print(obj.errors[NON_FIELD_ERRORS]) """ <ul class="errorlist nonfield"><li>密码不一致</li></ul> <ul class="errorlist nonfield"><li>密码不一致</li></ul> """ # obj.errors是一个字典 # - 对于Form组件错误信息 """ { __all__: [错误1,错误2] user: [错误1,错误2] password: [错误1,错误2] } """ return render(request, \'register.html\', {\'obj\': obj})
个人博客主页:
def home(request,site): """ #个人博客主页 :param request: :param site: :return: """ # condition= {} # type_id = int(kwargs.get(\'type_id\')) if kwargs.get(\'type_id\') else None # if type_id: # condition[\'article_type_id\'] = type_id # type_choice_list = models.Article.type_choices blog = models.Blog.objects.filter(site=site).first() # 创建一个博客对象 if not blog: return redirect(\'/\') # print(site) #按照:标签,分类,时间 # 标签 tag_list = models.Article2Tag.objects.filter(article__blog=blog).values(\'tag_id\', \'tag__title\').annotate(ct=Count(\'id\')) #分类 category_list = models.Article.objects.filter(blog=blog).values(\'category_id\',\'category__title\').annotate(ct=Count(\'nid\'))#queryset[字典1,字典2......] #时间 date_list = models.Article.objects.filter(blog=blog).extra(select={\'ctime\':"date_format(create_time,\'%%Y-%%m\')"}).values(\'ctime\').order_by(\'-ctime\').annotate(ct=Count(\'nid\')) #文章分页 all_count = models.Article.objects.all().count() page_info = PageInfo(request.GET.get(\'page\'), all_count, 2, \'/bingabcd.html\', 11) article_list = models.Article.objects.all()[page_info.start():page_info.end()] # #获取时间分组 # # date_list = models.Article.objects.filter(blog=blog).extra(select={\'c\':"date_format(create_time,\'%%Y-%%m\')"}).values(\'c\').order_by(\'-c\').annotate(ct=Count(\'nid\')) """ nid,title """ return render( request, \'home.html\', { \'site\':site,#博客后缀 \'blog\': blog,#博客对象 \'article_list\':article_list,#文章列表 \'page_info\':page_info,#分页 \'tag_list\':tag_list,#标签 \'category_list\':category_list,#分类 \'date_list\':date_list,#时间 } ) # 1.当前博客的所有文章
个人博客文章筛选:
#个人博客筛选 def home_filter(request,site,key,val): """ 个人博客筛选 :param request: :param site: :param key: :param val: :return: """ # blog = models.Blog.objects.filter(site=site).select_related(\'user\').first()#related_name直接连表,如果做for循环query_set对象时,减少查询次数 # print(blog) # if not blog: # return redirect(\'/\') blog = models.Blog.objects.filter(site=site).first() # 创建一个博客对象 print(blog) if not blog: return redirect(\'/\') #按照:标签,分类,时间 #标签 tag_list = models.Article2Tag.objects.filter(article__blog=blog).values(\'tag_id\',\'tag__title\').annotate(ct=Count(\'id\')) print(tag_list) print(tag_list.query) #分类 category_list = models.Article.objects.filter(blog=blog).values(\'category_id\',\'category__title\').annotate(ct=Count(\'nid\'))#queryset[字典1,字典2......] print(category_list) print(category_list.query) #时间 date_list = models.Article.objects.filter(blog=blog).extra(select={\'ctime\':"date_format(create_time,\'%%Y-%%m\')"}).values(\'ctime\').order_by(\'-ctime\').annotate(ct=Count(\'nid\')) print(date_list.query) print(\'1111\') #文章分页 all_count = models.Article.objects.all().count()#总页数 page_info = PageInfo(request.GET.get(\'page\'), all_count, 2, \'/bingabcd.html\', 11) if key == \'tag\': article_list = models.Article.objects.filter(tags__nid=val,blog=blog)[page_info.start():page_info.end()] #文章列表 print(article_list) # v = models.Article.objects.filter(blog=blog,article2tag__tag__title=val) # print(v.query) # #自定义第三张表 # #自己反向关联 # v = models.Article.objects.filter(blog=blog,article2tag__tag=val) # #通过M2M字段 # v = models.Article.objects.filter(blog=blog,tags__nid=val) elif key == \'category\': article_list = models.Article.objects.filter(category_id=val,blog=blog)[page_info.start():page_info.end()] #文章列表 print(article_list) else: # article_list = models.Article.objects.filter(create_time=val,blog=blog).all()[page_info.start():page_info.end()]#文章列表 article_list = models.Article.objects.filter(blog=blog).extra(where=["date_format(create_time,\'%%Y-%%m\')=%s"],params=[val,])[page_info.start():page_info.end()] print(article_list) return render( request, \'home_filter.html\', { \'blog\':blog, \'tag_list\':tag_list, \'category_list\':category_list, \'date_list\':date_list, \'article_list\':article_list, \'page_info\':page_info } )
查看文章详细页:
#查看文章详细页 def detail(request,*args,**kwargs):#文章详细 """ 查看文章详细页 :param request: :return: """ site = kwargs.get("site") nid = kwargs.get(\'nid\') url = request.path_info user_id = request.session.get(\'user_id\') # 博客信息 blog = models.Blog.objects.filter(site=site).first() if user_id: userinfo = models.UserInfo.objects.filter(nid=user_id).first() else: userinfo = False #文章 obj = models.Article.objects.filter(blog__site=site,nid=nid).first() print(obj) #分类列表 category_list = models.Article.objects.filter(blog__site=site).values(\'category__title\',\'category_id\').annotate(c=Count(\'nid\')) #标签列表 tag_list = models.Article.objects.filter(blog__site=site).values(\'tags__title\',\'tags__nid\').annotate(c=Count(\'nid\')) #时间列表 date_list = models.Article.objects.filter(blog=blog).extra(select={\'c\':"date_format(create_time,\'%%Y-%%m\')"}).values(\'c\').order_by(\'-c\').annotate(ct=Count(\'nid\')) comment_list = [] com = [] comment = enumerate(obj.comment_set.all()) for i,j in comment: com = [] com.append(i+1) com.append(j) comment_list.append(com) return render( request, \'article_detail.html\', { \'url\':url, \'obj\':obj, \'blog\':blog, \'date_list\':date_list, \'category_list\': category_list, \'tag_list\': tag_list, \'userinfo\':userinfo, \'comment\':comment_list, } )
文章中赞或者踩:
待补充:
博客系统后台管理:
后台管理:
组合筛选:
第一种方式:用for循环:
views.py
def lizhi(request,**kwargs): print(kwargs)#{\'article_type_id\': \'1\', \'category_id\': \'1\', \'tags_id\': \'0\'}#从url传过来的数据 condition = {} for k,v in kwargs.items(): kwargs[k] = int(v) if v != \'0\': condition[k] = v print(condition)#{\'article_type_id\': \'1\', \'category_id\': \'1\'} # 大分类 type_list = models.Article.type_choices print(type_list)#[(1, \'Python\'), (2, \'Linux\'), (3, \'OpenStack\'), (4, \'GoLang\'), (5, \'Car\')] #个人分类 category_list = models.Category.objects.filter(blog_id=1)# print(category_list)#<QuerySet [<Category: bingabcd-Python>, <Category: bingabcd-设计模式>, <Category: bingabcd-机器人>]> #个人标签 tag_list = models.Tag.objects.filter(blog_id=1) print(tag_list)#<QuerySet [<Tag: bingabcd-Python之路>, <Tag: bingabcd-Django>, <Tag: bingabcd-HTML>, <Tag: bingabcd-机器人>, <Tag: bingabcd-人工智能>]> # 对文章进行筛选 condition[\'blog_id\']=1 article_list = models.Article.objects.filter(**condition) print(article_list)#<QuerySet [<Article: bingabcd-Python>, <Article: bingabcd-机器人>, <Article: bingabcd-Python基本数据类型>, <Article: bingabcd-Django基础>]> return render(request, \'lizhi.html\', { \'type_list\':type_list, \'category_list\':category_list, \'tag_list\':tag_list, \'article_list\':article_list, \'kwargs\':kwargs } )
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> <style> .condition a{ display: inline-block; padding: 5px; } .condition a.active{ background-color: #204d74; color: white; } </style> </head> <body> <h3>筛选</h3> <div class="condition"> 大大分类: {% if kwargs.article_type_id == 0 %} <a class="active" href="/lizhi-0-{{ kwargs.category_id }}-{{ kwargs.tags__nid }}.html">全部</a> {% else %} <a href="/lizhi-0-{{ kwargs.category_id }}-{{ kwargs.tags__nid }}.html">全部</a> {% endif %} {% for row in type_list %} {% if row.0 == kwargs.article_type_id %} <a class="active" href="/lizhi-{{ row.0 }}-{{ kwargs.category_id }}-{{ kwargs.tags__nid }}.html">{{ row.1 }}</a> {% else %} <a href="/lizhi-{{ row.0 }}-{{ kwargs.category_id }}-{{ kwargs.tags__nid }}.html">{{ row.1 }}</a> {% endif %} {% endfor %} <div> 个人分类 <a href="#">全部</a> {% for row in category_list %} <a href="{{ row.nid }}">{{ row.title }}</a> {% endfor %} </div> <div> 个人标签 <a href="#">全部</a> {% for row in tag_list %} <a href="{{ row.nid }}">{{ row.title }}</a> {% endfor %} </div> <div> <h3>结果</h3> {% for row in article_list %} <h4><a href="#">{{ row.title }}</a></h4> <div>{{ row.summary }}</div> {% endfor %} </div> {# 大大分类:#} {# {% if kwargs.article_type_id == 0 %}#} {# <a class="active" href="/lizhi-0-{{ kwargs.category_id }}-{{ kwargs.tags__nid }}.html">全部</a>#} {# {% else %}#} {# <a href="/lizhi-0-{{ kwargs.category_id }}"></a>#} {# {% endif %}#} </div> </body> </html>
组合搜索功能还未完善:
#URL #urls.py # url(r\'^screen-(?P<article_type_id>\d+)-(?P<category_id>\d+)-(?P<article2tag__tag_id>\d+).html$\', views.screen), url(r\'^screen-(?P<article_type_id>\d+)-(?P<category_id>\d+)-(?P<tags__nid>\d+).html$\', views.screen), #视图函数 #views.py def screen(request,**kwargs): # print(kwargs) condition = {} for k,v in kwargs.items(): kwargs[k] = int(v) if v != \'0\': condition[k] = v print(condition) #大分类 type_list = models.Article.type_choices #个人分类 catagory_list = models.Category.objects.filter(blog_id=1) #个人标签 tag_list = models.Tag.objects.filter(blog_id=1) #进行筛选 condition[\'blog_id\']=1 article_list = models.Article.objects.filter(**condition) return render(request,\'screen.html\',{ \'type_list\':type_list, \'catagory_list\':catagory_list, \'tag_list\':tag_list, \'article_list\':article_list, \'kwargs\':kwargs, }) #模板语言 #screen.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> .condition a{ display: inline-block; padding: 5px; } .condition a.active{ background-color: #0a386a; color: white; } </style> </head> <body> <h3>筛选</h3> <div class="condition"> 大大分类: {% if kwargs.article_type_id == 0 %} <a class="active" href="/screen-0-{{ kwargs.category_id }}-{{ kwargs.tags__nid }}.html">全部</a> {% else %} <a href="/screen-0-{{ kwargs.category_id }}-{{ kwargs.tags__nid }}.html">全部</a> {% endif %} {% for row in type_list %} {% if row.0 == kwargs.article_type_id %} <a class="active" href="/screen-{{ row.0 }}-{{ kwargs.category_id }}-{{ kwargs.tags__nid }}.html">{{ row.1 }}</a> {% else %} <a href="/screen-{{ row.0 }}-{{ kwargs.category_id }}-{{ kwargs.tags__nid }}.html">{{ row.1 }}</a> {% endif %} {% endfor %} </div> <div class="condition"> 个人分类: <a href="#">全部</a> {% for row in catagory_list %} <a href="{{ row.nid }}">{{ row.title }}</a> {% endfor %} </div> <div class="condition"> 个人标签: <a href="#">全部</a> {% for row in tag_list %} <a href="{{ row.nid }}">{{ row.title }}</a> {% endfor %} </div> <h3>结果</h3> {% for row in article_list %} <div> <h4><a href="#">{{ row.title }}</a></h4> <div>{{ row.summary }}</div> </div> {% endfor %} </body> </html> 报障系统后台管理组合筛选
第二种方式:用simple_tag+filter
KindEditor上传图片:
参考文档:KindEditor
#URL路由 #urls.py url(r\'^upload_img.html$\', views.upload_img), #视图函数 #views.py def upload_img(request): import os # print(request.POST, request.FILES) # upload_type = request.GET.get(\'dir\') # 根据上传得文件类型控制上传得文件目录 file_obj = request.FILES.get(\'imgFile\') file_path = os.path.join(\'static/img\',file_obj.name) with open(file_path,\'wb\') as f: for chunk in file_obj.chunks(): f.write(chunk) dic = { \'error\':0, \'url\':\'/\'+file_path, \'message\':\'错误了...\' } import json return HttpResponse(json.dumps(dic)) #模板语言 #editor.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form method="POST" action="/editor.html" novalidate> {#如果不加novalidate,{{ obj.content }}会报错#} <p> 文章标题 {{ obj.title }} </p> {% csrf_token %} <div> <div>文章内容</div> <div> {{ obj.content }} </div> </div> <input type="submit" value="提交"> </form> <script src="/static/kindeditor-4.1.10/kindeditor-all.js"></script> <script> KindEditor.create("#i1",{ width: "700px", height: "300px", uploadJson: \'/upload_img.html\', extraFileUploadParams: { "csrfmiddlewaretoken":"{{ csrf_token }}" {# 需要添加CSRF验证#} } }) </script> </body> </html> KindEditor上传图片
补充:
文件上传其实内部就是iframe+form 伪Ajax操作
input type=\'file\' name=\'imgFile\' 提交
可以通过filePostName 更改默认name属性:
filePostName: \'fafafa\'
BeautifulSoup模块基本使用:
beautifulsoup4的基本使用 安装: pip3 install beautifulsoup4 导入模块: from bs4 import BeautifulSoup valid_tag = [] #只能设置标签名的白名单 valid_tag = {} #既能加标签名又能加标签的属性的白名单 tag.name 获取标签名 soup.find() #查找第一个标签 soup.find_all() #查找所有的p标签 tag.clear() #清除标签中的内容 tag.decompose() #清空标签中的内容并且删除标签 decode() soup对象转换成字符串 encode() soup对象转换成字节 #示例: content = """ <p id=\'i1\' a=\'123\' b=\'999\'> <script>alert(123)</script> </p> <p id=\'i2\'> <div> <p>asfjldjf</p> </div> <img id=\'i3\' src="/static/img\lang.jpg" alt="" /> </p> """ from bs4 import BeautifulSoup soup = BeautifulSoup(content,\'html.parser\') #设置名叫valid_tag的白名单: # valid_tag = [\'p\',\'img\',\'div\'] #只能放置标签名,列表形式 valid_tag = { #既能加标签名又能加标签的属性,字典形式。 \'p\':[\'class\',\'id\'], \'img\':[\'src\'], \'div\':[\'class\'] } # v=soup.find(name=\'p\',attrs={\'id\':\'i2\'}) #查找第一个p标签,并且id是i2 # print(v) # tag = soup.find(name=\'p\') #查找第一个p标签,生成的是对象的形式,可以通过“.”形式继续查找 # sc=tag.find(\'script\') # print(sc) # v=soup.find_all(name=\'p\') #查找所有的p标签 # print(v) # tags = soup.find_all() #查找所有的标签 # for tag in tags: #tag.name是标签名 # if tag.name not in valid_tag: #如果标签名不在白名单中则情况标签中的内容 # tag.clear() tags = soup.find_all() for tag in tags: if tag.name not in valid_tag: tag.decompose() #删除不再白名单中的标签 if tag.attrs: for k in list(tag.attrs.keys()): #{id:\'i1\',a=123,b=999} if k not in valid_tag[tag.name]: del tag.attrs[k] content_str=soup.decode() #去掉特殊标签后,拿到它的字符串 print(content_str) #打印过滤后的标签字符串 beautifulsoup4的基本使用
基于KindEditor和BeautifuSoup实现防止XSS攻击:
基于KindEditor和BeautifuSoup实现防止XSS攻击 #URL路由系统 #urls.py url(r\'^editor.html$\', views.editor), #可视化编辑器 url(r\'^see.html$\', views.see), #查看可视化编辑器生成的样式 url(r\'^upload_img.html$\', views.upload_img), #上传图片 #视图函数 #views.py CONTENT = "" from app01.forms import ArticleForm def editor(request): if request.method=="GET": obj = ArticleForm() return render(request,\'editor.html\',{\'obj\':obj}) else: obj = ArticleForm(request.POST) if obj.is_valid(): content = obj.cleaned_data[\'content\'] global CONTENT CONTENT = content print(content) return HttpResponse("...") def see(request): return render(request,\'see.html\',{\'con\':CONTENT}) def upload_img(request): import os # print(request.POST, request.FILES) # upload_type = request.GET.get(\'dir\') # 根据上传得文件类型控制上传得文件目录 file_obj = request.FILES.get(\'imgFile\') file_path = os.path.join(\'static/img\',file_obj.name) with open(file_path,\'wb\') as f: for chunk in file_obj.chunks(): f.write(chunk) dic = { \'error\':0, \'url\':\'/\'+file_path, \'message\':\'错误了...\' } import json return HttpResponse(json.dumps(dic)) #模板语言 #editor.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form method="POST" action="/editor.html" novalidate> {# 如果不加novalidate,{{ obj.content }}会报错#} <p> 文章标题 {# <input type="text" name="title">#} {{ obj.title }} </p> {# <p>#} {# 选择分类#} {# <select name="" id="">#} {##} {# </select>#} {# </p>#} {# <p>#} {# 选择标签#} {# <input type="checkbox">#} {# <input type="checkbox">#} {# <input type="checkbox">#} {# <input type="checkbox">#} {# </p>#} {% csrf_token %} <div> <div>文章内容</div> <div> {# <textarea name="content" id="i1" cols="30" rows="10"></textarea>#} {{ obj.content }} </div> </div> <input type="submit" value="提交"> </form> <script src="/static/kindeditor-4.1.10/kindeditor-all.js"></script> <script> KindEditor.create("#i1",{ width: "700px", height: "300px", {# items: [ \'source\', \'|\', \'undo\', \'redo\', \'|\', \'preview\', \'print\', \'template\', \'code\', \'cut\', \'copy\', \'paste\',],#} {# noDisableItems: [\'undo\',\'redo\'],#} {# designMode: false,#} {# resizeType:1,#} uploadJson: \'/upload_img.html\', extraFileUploadParams: { "csrfmiddlewaretoken":"{{ csrf_token }}" {# 需要添加CSRF验证#} } }) </script> </body> </html> #Form组件 #forms.py from django.forms import Form from django.forms import fields from django.forms import widgets from django.core.exceptions import ValidationError class ArticleForm(Form): title = fields.CharField(max_length=64) content = fields.CharField( widget=widgets.Textarea(attrs={\'id\':\'i1\'}) ) def clean_content(self): from bs4 import BeautifulSoup valid_tag = { \'p\': [\'class\', \'id\'], \'img\': [\'src\'], \'div\': [\'class\'] } old=self.cleaned_data[\'content\'] soup = BeautifulSoup(old, \'html.parser\') tags = soup.find_all() for tag in tags: if tag.name not in valid_tag: tag.decompose() # 删除不再白名单中的标签 if tag.attrs: for k in list(tag.attrs.keys()): # {id:\'i1\',a=123,b=999} if k not in valid_tag[tag.name]: del tag.attrs[k] content_str = soup.decode() return content_str 防止XSS攻击
补充:
防止XSS攻击为什么不用黑名单,要用白名单?
使用白名单过滤html标签比黑名单操作起来更简单,把攻击锁定在自己可控制范围内。
参考博客:http://www.cnblogs.com/wupeiqi/articles/6283017.html