博客开发之旅:
#回滚,数据存储失败时,还原修改操作
from django.db importtransaction
with transaction.atomic():
do...
...#==========自定义form表单验证----------====#自定义验证规则
defmobile_validate(value):
mobile_re= re.compile(r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$')if notmobile_re.match(value):raise ValidationError('手机号码格式错误')#使用自定义验证规则
phone = fields.CharField(validators=[mobile_validate, ],
error_messages={'required': '手机不能为空'},
widget=widgets.TextInput(attrs={'class': "form-control",'placeholder': u'手机号码'}))#多选
course_id =fields.MultipleChoiceField(
choices=models.Course.objects.all().values_list('id','title'),
widget=widgets.SelectMultiple(attrs={'class':'form-control'})
)
View Code
#+============+++++++++++==扩展Django自带的用户认证表=========+++++++++++++===
from django.contrib.auth.models importAbstractUserclassUserInfo(AbstractUser):"""用户信息表"""nid= models.AutoField(primary_key=True)
phone= models.CharField(max_length=11, null=True, unique=True)
avatar= models.FileField(upload_to="avatars/", default="avatars/default.png", verbose_name="头像")
create_time= models.DateTimeField(auto_now_add=True)
blog= models.OneToOneField(to="Blog", to_field="nid", null=True,on_delete=models.CASCADE)def __str__(self):returnself.username#在settings中告诉Django项目用哪张表做认证
AUTH_USER_MODEL = 'app01.UserInfo'
from django.contrib importauth
user= authenticate(username='theuser',password='thepassword')#即验证用户名以及密码是否正确,一般需要username 、password两个关键字参数。#如果认证成功(用户名和密码正确有效),便会返回一个 User 对象。
user= authenticate(username=username, password=password)if user is notNone:
login(request, user)#该函数接受一个HttpRequest对象,以及一个经过认证的User对象。#该函数实现一个用户登录的功能。它本质上会在后端为该用户生成相关session数据。
from django.contrib.auth importlogoutdeflogout_view(request):
logout(request)#该函数接受一个HttpRequest对象,无返回值。#当调用该函数时,当前请求的session信息会全部清除。该用户即使没有登录,使用该函数也不会报错。
if notrequest.user.is_authenticated():pass
#is_authenticated()#用来判断当前请求是否通过了认证。
#auth 给我们提供的一个装饰器工具,用来快捷的给某个视图添加登录校验。
from django.contrib.auth.decorators importlogin_required
@login_requireddefmy_view(request):pass
#若用户没有登录,则会跳转到django默认的 登录URL '/accounts/login/ ' 并传递当前访问url的绝对路径
(登陆成功后,会重定向到该路径)。LOGIN_URL = '/login/' #这里配置成你项目登录页面的路由
#create_user()#auth 提供的一个创建新用户的方法,需要提供必要参数(username、password)等。
from django.contrib.auth.models importUser
user= User.objects.create_user(username='用户名',password='密码',email='邮箱',...)#create_superuser()#auth 提供的一个创建新的超级用户的方法,需要提供必要参数(username、password)等。
from django.contrib.auth.models importUser
user= User.objects.create_superuser(username='用户名',password='密码',email='邮箱',...)#check_password(password)#auth 提供的一个检查密码是否正确的方法,需要提供当前请求用户的密码。密码正确返回True,否则返回False。
ok = user.check_password('密码')#set_password(password)#auth 提供的一个修改密码的方法,接收 要设置的新密码 作为参数。
注意:设置完一定要调用用户对象的save方法!!!
user.set_password(password='')
user.save()
极验: https://docs.geetest.com/install/deploy/server/python
pip install geetest
View Code
# +++++++++++++++++++++++文件上传++++++++++++++++++++
viewsfrom django.views.decorators.csrf importcsrf_exempt
@csrf_exemptdefupload(request):if request.method == 'POST':
file_obj= request.FILES.get('file')
with open('upload/'+file_obj.name,'wb')as f:for i infile_obj.chunks():
f.write(i)return render(request,'upload.html')
html
View Code
#++++++++++++==文档加载完之后才执行 JS 的三种方式===++++++++++++
var a= document.getElementById('username');
alert(a);
};
$(document).ready(function () {
var a= document.getElementById('default_avatar');
alert(a);
});
$(function () {
var a= document.getElementById('default_avatar');
alert(a);
})
View Code
#+++++++++++++++++====头像预览====++++++++++++++++
选择头像
#
var fileReader=new FileReader();//读取到当前选中的文件//console.log(this.files[0]);
fileReader.readAsDataURL(this.files[0]);
fileReader.οnlοad=function () {
$('#default_avatar').attr('src',fileReader.result);
}
})
View Code
#-------------Form表单验证在渲染成HTML标签时显示错误信息----------------
{{ obj.username.label }}
{{ row.label }}
View Code
# +++++++++++++++++++全局钩子验证密码一致性 以及实时跟新数据+++++++++++++++++++++
classRegForm(Form):
...
re_password=fields.CharField(
min_length=6,
label="确认密码",
widget=widgets.PasswordInput(
attrs={"class": "form-control"},
render_value=True,
),
error_messages={"min_length": "确认密码至少要6位!","required": "确认密码不能为空",
}
)
user_type=fields.ChoiceField(
choices=models.UserType.objects.values_list('id','caption')
)#重写全局的钩子函数,对确认密码做校验
defclean(self):
password= self.cleaned_data.get('password')
re_password= self.cleaned_data.get('re_password')if re_password and password !=re_password:
self.add_error('re_password',ValidationError('两次密码不一致!'))else:return self.cleaned_data #注意返回
#在使用选择标签时,需要注意choices的选项可以从数据库中获取,但是由于是静态字段
#***获取的值无法实时更新***,那么需要自定义构造方法从而达到此目的。
def __init__(self, *args, **kwargs):
super(RegForm,self).__init__(*args, **kwargs)
self.fields['user_type'].choices = models.UserType.objects.values_list('id','caption')
View Code
# ++++==+++__++===-+_+_===# 自己生成验证码图片 # ++++==+++__++===-+_+_===#
from PIL importImage, ImageDraw, ImageFont
img_obj= Image.new('RGB',(220,40),random_color()) #图片对象
draw_obj = ImageDraw.Draw(img_obj) #画笔对象
font_obj = ImageFont.truetype('static/fonts/kumo.ttf', 40) #字体对象
char_list = random_char() #验证码字符串
request.session["code_img"] = "".join(char_list) #将字符串保存到session会话
for i in range(len(char_list)): #将字符画到图片上
draw_obj.text((10+50*i,0),char_list[i],fill=random_color(),font=font_obj)#draw_obj.line((begin,end),fill=random_color(),width=random.randint(1,4)) # 画线条#draw_obj.point(width, height, fill=random_color()) # 画点
draw_obj.arc((x, y, x+z, y+z), 0, 360, fill=random_color()) #画弧线 圆
from io importBytesIO
io_obj= BytesIO() #将生成的图片数据保存在io对象中
img_obj.save(io_obj, "png") #从io对象里面取上一步保存的数据
data =io_obj.getvalue()returnHttpResponse(data)++++
$('#get_code').click(function () {//点击图片刷新验证码
$(this)[0].src+= "?";
});++++
View Code
#+==================# 重写局部钩子函数,对用户名做校验和ajax实时检验===========================+
classRegForm(Form):
username=fields.CharField(
max_length=16,
label="用户名",
error_messages={"max_length": "用户名最长16位","required": "用户名不能为空",
},
widget=widgets.TextInput(
attrs={"class": "form-control"},
)
)defclean_username(self):
username= self.cleaned_data.get('username')
is_exist= models.UserInfo.objects.filter(username=username)ifis_exist:
self.add_error('username',ValidationError('用户名已存在'))else: #重写的是局部钩子,所以返回检验的字段
returnusername#username输入框失去焦点,使用ajax检验用户名是否存在
@csrf_exemptdefcheck_username_exist(request):
ret= {'status':False,'msg':None}
is_exist= models.UserInfo.objects.filter(username=request.POST.get('username'))ifis_exist:
ret['status']=True
ret['msg']='用户名已存在'
returnHttpResponse(json.dumps(ret))returnHttpResponse(json.dumps(ret))#
#取消浏览器自动匹配#$('#id_username').on('input',function () { # 内容变动就提交$('#id_username').blur(function () {
$.ajax({
url:'/check_username_exist/',
data: {'username': $(this).val()},
method:'post',
dataType:'json',
success: function (data) {if(data.status) {
$('#id_username').next().text(data.msg);
console.log(data.msg);
}
}
})
})#Django admin 使用#在app/admin.py文件中注册表
from django.contrib importadminfrom app01 importmodels
admin.site.register(models.UserInfo)
admin.site.register(models.Blog)#在settings配置显示中文
LANGUAGE_CODE = 'zh-hans'
classUserInfo():
...classMeta:
verbose_name= '用户' #给表起名
verbose_name_plural = verbose_name #显示复数也用'用户'来显示
在admin后台中显示中文表名
View Code
#=========== # Django用户上传的都叫media文件==================#setting.py#media配置,用户上传的文件都默认放在这个文件夹下
MEDIA_ROOT = os.path.join(BASE_DIR,"media")
MEDIA_URL= "/media/"
#urls.py
from django.views.static importservefrom django.conf importsettings
re_path('media/(?P.*)$',serve,{"document_root":settings.MEDIA_ROOT}),#做了media配置,用户上传文件都会在media/xx中。
View Code
#_+_+_+_+_+_+_+_+_+_+_+导入Django,单独测试某个功能_+_+_+_+_+_+_+_+_+_+_+_+_+
test.pyimportosif __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', '博客.settings')importdjango
django.setup()from app01 importmodels
obj=models.UserInfo.objects.all()print(obj.query)
View Code
# -=======----博客文章-=======----
ORM中values或者values_list 里面写什么字段,就相当于select 什么字段
ret= models.Employee.objects.all().values("dept", "age")
相当于:
SELECT `employee`.`dept`, `employee`.`age` FROM `employee` LIMIT21; args=()2. ORM中 annotate 前面是什么就按照什么分组!from django.db.models importAvg
ret= models.Employee.objects.values("province").annotate(a=Avg("salary")).values("province", "a")
相当于:
SELECT `employee`.`province`, AVG(`employee`.`salary`) AS `a` FROM `employee` GROUP BY `employee`.`province` ORDER BY NULL LIMIT21; args=()3. extra -->在执行ORM查询的时候执行额外的SQL语句#查询person表,判断每个人的工资是否大于2000
ret =models.Person.objects.all().extra(
select={"gt": "salary > 2000"}
)
相当于:
SELECT (salary> 2000) AS `gt`, `person`.`id`, `person`.`name`, `person`.`salary`, `person`.`dept_id` FROM `person` LIMIT 21; args=()4. 直接执行原生的SQL语句,类似pymysql的用法from django.db importconnection
cursor= connection.cursor() #获取光标,等待执行SQL语句
cursor.execute("""SELECT * from person where id = %s""", [1])
row=cursor.fetchone()print(row)#=====++++++创建数据库表,插入时间++++++=======
mysql>create table test(d date, dt datetime, t time);
mysql>insert into test(d,dt,t) values(now(),now(),now());
mysql>select date_format(dt,'%Y-%m') from test; #格式化,只看年月
View Code
#=++++++++++++==========+++++母板,子板,自定义templates+++====+++++++++++===========
母板
{{ blog.title }}{% get_left_menu username %}
{% endblock %}
子板
{% extends 'base.html' %}
{% block page-main %}
。。。。。。。
{% endfor %}
自定义templates
在app下新建目录templatetags,在新建目录下新建文件my_tags.pyfrom django importtemplatefrom app01 importmodelsfrom django.db.models importCount
register= template.Library() #固定写法
@register.inclusion_tag("left_menu.html")defget_left_menu(username):
user= models.UserInfo.objects.filter(username=username).first()
blog=user.blog#查询文章分类及对应的文章数
category_list = models.Category.objects.filter(blog=blog)#查文章标签及对应的文章数
tag_list = models.Tag.objects.filter(blog=blog).annotate(c=Count("article")).values("title", "c")#按日期归档
#archive_list = models.Article.objects.filter(user=user).extra(
#select={"archive_ym": "date_format(create_time,'%%Y-%%m')"}
#).values("archive_ym").annotate(c=Count("nid")).values("archive_ym", "c")
return{"category_list":category_list,"tag_list": tag_list,
}
创建left_menu.html
{{ category.title }}({{ category.article_set.all.count }})
{% endfor %}{{ tag.title }}({{ tag.c }})
{% endfor %}View Code
# ===========-----====-----====-------点赞 js-------======-----======-----=============
defdianzan_up_down(request):
ret= {'status':False,'msg':None}
article_id= request.POST.get('article_id')
is_up= json.loads(request.POST.get('is_up'))
user=request.userifuser:try:
models.ArticleUpDown.objects.create(user=user,article_id=article_id,is_up=is_up)
models.Article.objects.filter(nid=article_id).update(up_count=F('up_count')+1)
ret['status'] =True
ret['is_up'] =is_upreturnHttpResponse(json.dumps(ret))exceptException as e:
is_up= models.ArticleUpDown.objects.filter(user=user,article_id=article_id).first().is_up
ret['first_action']=is_upreturnHttpResponse(json.dumps(ret))
ret['msg'] = '请先登录'
returnHttpResponse(json.dumps(ret))
{{ article.up_count }}
{{ article.down_count }}
$('#div_digg .action').click(function () {
var is_up= $(this).hasClass('diggit');
var crticle_id= "{{ article.pk }}";#var article_id = $('.info').attr('article_id');当JS保存为静态文件时,获取文章id
$.ajax({
url:'/blog/article/up_down/',
type:'post',
data: {'article_id': crticle_id,'is_up': is_up,'csrfmiddlewaretoken': $('[name=csrfmiddlewaretoken]').val()
},
dataType:'json',
success: function (data) {if(data.status) {if(data.is_up) {
var count= $('#digg_count').text();
count= parseInt(count) + 1;
$('#digg_count').text(count);
}else{
var count= $('#bury_count').text();
count= parseInt(count) + 1;
$('#digg_count').text(count);
}
}else{if(data.msg) {
$('#digg_tips').text(data.msg);
}else{if(data.first_action) {
$('#digg_tips').text('您已经推荐过啦');
}else{
$('#digg_tips').text('您已经反对过啦');
}
}
setTimeout(function () {
$("#digg_tips").html("")
},1000)
}
}
})
})
#========= 响应ajax,数据直接使用,不用写dataType:'json' =========
from django.http importJsonResponsereturn JsonResponse({'',''})
View Code
# +++++++++++++++++++使用JS动态绑定事件+++++++++++++++++++++++
//後面添加的元素無法綁定事件,需預加載
$(document).on('click','#reply',function () {
$("#comment_content").focus();
var v= "@" + $(this).attr("username") + "\n";
$("#comment_content").val(v);
pid= $(this).attr("comment_id")
});
View Code
#_+__________++++++++评论树例子+__________+++++++++
from django.http importJsonResponsedefcomment_tree(request,article_id):
comment_list= list(models.Comment.objects.filter(article_id=article_id).values("pk","content","parent_comment_id","create_time",'user__username'))print(comment_list) #将 转为列表。若直接json.dumps(comment_list)会报错!
return JsonResponse(comment_list,safe=False)#静态文件中(外部js文件)需要使用的值,最好在渲染的时候将值作为属性存到标签中。方便取值。
$(function () {//获取评论列表
$.ajax({
url:'/blog/comment/' + '{{ article.pk }}/',// dataType:'json',// returnHttpResponse(json.dumps(dict(enumerate(comment_list))))// enumerate(comment_list,start=1)指定起始值,那么下面的.each index就不用加值了,不过这个麻烦// 瞎折腾得是,以上3行 等价 return JsonResponse(comment_list,safe=False)
success: function (data) {
$.each(data, function (index, comment_dict) {
index= index + 1;
var s= '
var pid=comment_dict.parent_comment_id;
$('[comment_id="' + pid + '"]').append(s);
}else{//根评论
$('.comment_tree').append(s);
}
})
}
});
pid= ""; //有值即回复别人的评论内容,无值评论文章//子评论设置pid
$(document).on('click', '#reply', function () {
var v= "@" + $(this).attr("username") + "\n";
$("#comment_content").focus().val(v);
pid= $(this).attr("comment_pk");
});//提交评论
$('#comment_btn').click(function () {
var content= $('#comment_content').val();
var article_id= $('#info').attr('article_id');
$.ajax({
url:'/blog/comment/',
type:'post',
data: {'content': content, 'article_id': article_id, 'pid': pid,
csrfmiddlewaretoken: $("[name='csrfmiddlewaretoken']").val(),
},
success: function (data) {
var s= '
$('.comment_tree').append(s);
$('#comment_content').val('');
pid= "";
}
})
})
})
View Code
# ===========================富文本编辑器=kindeditor===============================
window.editor= K.create('#article_content', {
width:'800px',
uploadJson:"/upload/", //上传图片什么的需要填参数
extraFileUploadParams: {"csrfmiddlewaretoken": $("[name='csrfmiddlewaretoken']").val()
},
filePostName:"upload_file",//request.FILE.get('') 文件键名
});
});上传图片defupload(request):if request.method == 'POST':
file_obj= request.FILES.get('upload_file')
path= 'media/add_article/'+file_obj.name
with open(path,'wb')as f:for i infile_obj.chunks():
f.write(i)
res={'error':0, #没有出错
'url':path,
}returnHttpResponse(json.dumps(res))return HttpResponse('')
提交文章#使用beautifulSoup过滤文章中的JS代码,防止XSS攻击
defadd_article(request):if request.method=="POST":
title=request.POST.get('title')
article_content=request.POST.get('article_content')
user=request.userfrom bs4 importBeautifulSoup
bs= BeautifulSoup(article_content,'html.parser')#过滤非法字符
for tag inbs.find_all():#print(tag.name)
if tag.name in ['script','link']:
tag.decompose()
desc= bs.text[0:150]+'...'article_obj= models.Article.objects.create(user=user,title=title,desc=desc)
models.ArticleDetail.objects.create(content=str(bs),article=article_obj)return redirect('/blog/%s/'%request.user.username)return render(request,'add_article.html')#orm查询,基于对象查询(子查询),反向查询按表名小写_set.all()#基于queryset和__查询(join查询)正向查询:按字段 反向查询:表名小写#select publish.email from Book#left join Publish on book.publish_id=publish.nid#where book.title="python"#按逻辑来,对象查询是基于单个对象!?,join只要连上表就能拿值!。
View Code
# ———————————————————————————————————简单使用admin—————————————————————————————————————
from django.utils.safestring importmark_safefrom app01 importmodelsclassUserInfoConfig(admin.ModelAdmin):defdeletes(self):return mark_safe("删除")
list_display= ["username","email","create_time",'blog',deletes]#在admin管理页面,显示出用户表的用户信息字段,deletes是自定义的跳转链接
list_display_links= ["email"]#设置哪个字段可以点击跳转到编辑当前页信息的页面
list_filter=["username","email","create_time",'blog']#筛选功能,按字段条件筛选,指定多个字段组合筛选。
list_editable=["username",'blog']#此配置需要有list_display_links = ["email"]配置才能生效,即在当前页编辑其他字段信息,效果和直接在被编辑字段的编辑页面相同
search_fields=["username","email"]#添加搜索功能,以列表中的字段过滤出的信息后进行查找
defpatch_init(self,request,queryset):
queryset.update(price=100)
patch_init.short_description= "批量初始化"actions=[patch_init,]#添加一个批量操作选项。传入执行方法名
change_list_template="login.html"
#自己的后台管理页面。
View Code
# -------------------Xadmin----------------------
流程1、启动
在settings文件中配置上'Xadmin.apps.XadminConfig',
将会自动执行ready方法,查找所有app中的Xadmin模块
autodiscover_modules('Xadmin')2、注册
单例模式from Xadmin.service.Xadmin importsitefrom app01 importmodels
site.registry(models.Test)3、设计url
为每个app下的model设计增删改查url127.0.0.1:8008/admin/app01/book/1/change/ :改id=1的数据#url的路由分发
path('test/',([re_path('\d+',func),re_path('(\d+)',([],None,None)),],None,None))#url
path('xadmin/', Xadmin.site.urls),#Xadmin组件 -> apps.py
from django.apps importAppConfigfrom django.utils.module_loading importautodiscover_modulesclassXadminConfig(AppConfig):
name= 'Xadmin'
defready(self):
autodiscover_modules('Xadmin')#Xadmin -> service -> Xadmin.py
from django.urls importpath,re_pathfrom django.shortcuts importrender,HttpResponse,redirectclassModelXadmin(object):def __init__(self,model,site):
self.model=model
self.site=sitedeflist_view(self,request):return HttpResponse('list_view')defadd_view(self,request):return HttpResponse('add_view')defchange_view(self,request,id):return HttpResponse('change_view')defdelete_view(self,request,id):return HttpResponse('delete_view')defget_urls2(self):
temp=[]
temp.append(re_path('^$',self.list_view))
temp.append(re_path('^add/$',self.add_view))
temp.append(re_path('^(\d+)/change/$',self.change_view))
temp.append(re_path('^(\d+)/delete/$',self.delete_view))returntemp
@propertydefurls2(self):#路由,某个表的增删改查url
returnself.get_urls2(),None,NoneclassXadminSite(object):def __init__(self,name='admin'):
self._registry={}defget_urls(self):
temp=[]for model,xadmin_class_obj inself._registry.items():
app_name=model._meta.app_label
model_name=model._meta.model_name
temp.append(re_path('^%s/%s/'%(app_name,model_name),xadmin_class_obj.urls2))returntemp
@propertydefurls(self):#路由,app下的某个表url
returnself.get_urls(),None,Nonedef registry(self,model,xadmin_class=None,**kwargs):if notxadmin_class:
xadmin_class=ModelXadmin
self._registry[model]=xadmin_class(model,self)
site=XadminSite()#app01 -> Xadmin.py
from Xadmin.service.Xadmin importsitefrom app01 importmodels
site.registry(models.Test)
笔记暂断
View Code
# =-=-=-=-=-=-=-=-=rbac基于角色的访问权限控制,大致流程=--==-=-=-=-=-=-=-
#rbac -> views.py
from django.shortcuts importrender,redirectfrom rbac.models import *
defrbac_list(request):'''用户权限信息'''role_list=Role.objects.all()
user= Role.objects.values('o2o_user__user_id','o2o_user__user__username')
user_list=[]for item inuser:if item['o2o_user__user_id']:
user_list.append((item['o2o_user__user_id'],item['o2o_user__user__username']))
obj=roleForm()return render(request,'rbac.html',{'role_list':role_list,'user_list':user_list,'obj':obj})from django.forms importForm,fields,widgetsclassroleForm(Form):
users=fields.ChoiceField(
choices=O2o_User.objects.values_list('user__nid','user__username')
)
roles=fields.MultipleChoiceField(
choices=Role.objects.values_list('pk','title')
)defrbac_edit(request):'''修改权限'''id= request.POST.get('users')
roles= request.POST.getlist('roles')
obj= roleForm({'users':id,'roles':roles})
res=obj.is_valid()ifres:
obj= O2o_User.objects.filter(user_id=id).first()
obj.roles.set(roles)return redirect('/rbac/')#中间件过滤请求
importrefrom django.utils.deprecation importMiddlewareMixinfrom django.shortcuts importHttpResponse,redirectclassValidPermission(MiddlewareMixin):defprocess_request(self,request):
current_path=request.path_info
pass_url= ["/index/",'/info/','/register/.*','/login/.*','/logout/','/admin/.*',]#白名单直接放行
for rule inpass_url:
ret=re.match(rule, current_path)ifret:returnNone#不在白名单内,判断是否登录用户。
if notrequest.user.username:return redirect('/login/')
permission_dict= request.session.get('permission_dict')for item inpermission_dict.values():
urls= item['url']for rule inurls:
rule= '^%s$'%rule
ret=re.match(rule,current_path)ifret:#注入权限,用于控制template模板显示增删改
request.action = item['action']returnNoneprint('没有权限%s'%current_path)return HttpResponse('没有权限%s'%current_path)#rbac -> permission.py
from rbac importmodelsdefvalid_permission(request):'''提取用户权限并存储到session'''
#print('ssssssssssssssss',request.path_info,user.email)
res = models.O2o_User.objects.filter(user=request.user).values('roles__permissions__url',#'roles__permissions__title',
'roles__permissions__action','roles__permissions__group_id',)
per={}for item inres:if item['roles__permissions__group_id'] inper:
per[item['roles__permissions__group_id']]['url'].append(item['roles__permissions__url'])#per[item['roles__permissions__group_id']]['title'].append(item['roles__permissions__title'])
per[item['roles__permissions__group_id']]['action'].append(item['roles__permissions__action'])else:
per[item['roles__permissions__group_id']] ={'url':[item['roles__permissions__url'],],#'title':[item['roles__permissions__title'],],
'action':[item['roles__permissions__action'],]
}
request.session['permission_dict'] =perprint(per)#使用auth认证,登录成功就将用户权限保存到session中
auth.login(request,user)
valid_permission(request)#在rbac中创建一个模板用于rbac权限设置,用户权限不满足就只渲染部分功能。
View Code
# -===-=-=-=-=-=-=-=-=-=-=-=-=-返回顶部=-=-=-=-=-=-=-=-
返回顶部
var $height=$(window).scrollTop();if ($height > 200) {
$('#back_top').removeClass('hidden');
}else{
$('#back_top').addClass('hidden');
}
})
$('#back_top').click(function () {
$('body,html').animate({
scrollTop: 0
},1000);
})
View Code
# -=-=-=-=-=-=-=-ajax请求后端返回对象,前端直接使用
comment_list = list(models.Comment.objects.filter(article_id=article_id).values("pk","content"))return JsonResponse(comment_list, safe=False) 传送对象
success: function (data) {
$.each(data, function (index, comment_dict) {
comment_dict.pk
}}
View Code
#-=-=-=-==========页面跳转=-=-=-=-=-=-=-=-=-
//以下方式直接跳转
window.location.href='hello.html';//以下方式定时跳转
setTimeout("javascript:location.href='hello.html'", 5000);
#结合了倒数的javascript实现
setInterval("redirect()", 1000);
function redirect()
{
document.getElementById('totalSecond').textContent = --second;if (second < 0) location.href = 'hello.html';
}
View Code
'
'#' + index + '楼\n' +
'' + comment_dict.create_time + '\n' +
' \n' +
'
回复\n' +'
'
'