Django组件介绍html
分页器的使用前端
Formpython
modelFormgit
ormweb
cookie和sessionajax
中间件sql
信号数据库
分页器在页面中很是常见,当数据库条数数据过多时,页面一次性显示很差看,咱们就可使用页面器,将数据分几回显示后端
一个简单的分页功能,能够导入用
page_num = request.GET.get('page','1') try: page_num = int(page_num) if page_num <=0: page_num = 1 except Exception as e: page_num =1 #总数量 all_count = len(userlist) #每页显示为10 页 per_num = 10 #总页码数 total_page_num, more =divmod(all_count,per_num) if more: total_page_num += 1 #最多显示的页面数 max_show = 11 half_show = max_show//2 if total_page_num < max_show: page_start = 1 page_end = total_page_num elif page_num <= half_show: page_start =1 page_end =max_show elif page_num + half_show > total_page_num: page_start = total_page_num-max_show +1 page_end = total_page_num else: #起始页面 page_start = page_num - half_show #终止页面 page_end = page_num + half_show start =(page_num-1) * per_num end =page_num*per_num page_list = [] if page_num == 1: page_list.append('<li class="disabled"><a>上一页</a></li>') else: page_list.append('<li ><a href="?page={}">上一页</a></li>'.format(page_num - 1)) for i in range(page_start, page_end + 1): if i == page_num: page_list.append('<li class="active" ><a href="?page={}">{}</a></li>'.format(i, i)) else: page_list.append('<li><a href="?page={}">{}</a></li>'.format(i, i)) if page_num == total_page_num: page_list.append('<li class="disabled"><a>下一页</a></li>') else: page_list.append('<li><a href="?page={}">下一页</a></li>'.format(page_num + 1)) page_html = ''.join(page_list) return render(request, 'user_list.html', {'users': userlist[start:end], 'page_html': page_html})
django框架提供了一个form类,来处理web开发中的表单相关事项.form最常作的是对用户输入的内容进行验证,为此django的forms类提供了全面的内容验证和保留用户上次输入数据的支持
form组件的两大功能:
---对用户提交的内容进行验证(from表单/ajax)
---表留用户上次输入的内容
form组件的几大用处:
1.校验字段功能
1.首先先到导入forms这个模块 from django import forms 2.本身写一个类,并继承forms.Form class Myform(forms.Form): #这行代码的意思,name这字段最长为8,最短为3 name=forms.charField(max_length=8) def index(request): dic={'name':'zh'} #这里就是类的实例化,传的参数必须为一个字典 myform =Myform(dic) #这是对象的绑定方式,它的返回值就是一个布尔值 # True表示你传的dic这个字典知足form里的条件,False就是不知足 # 咱们能够经过判断它,再进行逻辑操做,好比该字段符合你的要求,再怎么操做 if myform.is_valid(): return HttpResponse('校验成功') # 走到这一步,表明当中有字段不符合要求 # 它的返回值是一个对象,可是它继承了字典,因此你能够经过get取到错误提示 # 对了,你传的字典的key值必需要和建立的类(Myform)要对应,而且只能多,不能少 # name_error = myform.errors.get('name') # 这样你能够取到name字段出错的缘由了 name_error=myform.errors return HttpResponse('校验失败') ## 总结下:一、Myform的实例化必须传字典 2、is_valid()返回值是布尔类型 三、errors 调用这个方法,返回值是对象,你能够经过get取值
2.渲染标签功能
form组件能够在视图函数中使用,也能够在模板中使用
渲染方式一: <form action='' method='post'> 用户名:{{myform:name}} <br> <input type='submit' value = '提交'></input> </form> # 这里的{{myform:name}} 和你写input框是同样的效果,就是属性比input框多一点 渲染方式二(推荐使用): <form action='' method='post'> {% for foo in myform%} {{ foo.lable }} : {{ foo }} <br> <input type='submit' value = '提交'></input> </form> # 页面显示都是同样的,foo.lable不是用户名,是name,可是你能够在建立Myform类时 # 在CharFiel中添加lable='用户名',这样就好了。 渲染方式三: <form action='' method='post'> {{ myform.as_p }} <input type='submit' value = '提交'></input> </form> # 对,方式三就是这么简单,可是拓展性太差了,对不对,因此不推荐使用它
3.渲染错误信息功能
渲染错误信息,以前不是写了error这个方法嘛,他就是装着错误信息的对象, 其实就是让它渲染到页面上,这不就是很简单嘛 拿渲染方式二来举例子吧: <form action='' method='post'> {% for foo in myform%} {{ foo.lable }} : {{ foo }} <span>{{foo.errors.0}}</span><br> <input type='submit' value = '提交'></input> </form> # 来说下为何不是用get去取错误信息,首先这个foo是什么?它就是你建立的字段 # 因此直接经过索引取值就行了,那么就应该知道foo.errors貌似就是一个列表对吧 # 模板渲染时我在后台渲染好了,再返回到前台的,那我能够不能够将错误信息传到前台 # 让前台执行DOM操做进行渲染呢? # 我以为太麻烦,何况前端我。。。(你懂的)
4.组件的参数配置
其实在些Myform,下面的字段还有不少参数,我就写写大概有什么用 max_length # 表明该字段最长为多少 min_length # 表明该字段最短为多少 error_messages # 这是设置错误信息的属性 # 例子 error_messages= {'max_length': '最长八位', 'min_length': '最短三位', 'required': '不能为空'} required # 默认值为True,意思是你传来的字段必须有它,没有的话校验失败 widget=widgets.TextInput() # 你在模板渲染的时候,就会渲染成Input框,type为text 还有其余类型的input框,本身在看看吧 对了,在TextInput(),你能够为input添加属性,attrs={'class':'abc'} 写在括号里面 lable #这个是否是上面讲到了,lable='用户名'
5.钩子
局部钩子 局部钩子说白了就是写一个函数,可是这个函数名必须为clean_name,这个name是能够改变的, 你定义的类里,你想对哪一个字段写钩子函数,这个name就为那个字段的名字,好比我想为password这个 字段写钩子函数,那函数名就为clean_password,就这样。 那这个局部钩子有什么用了? 首先你的程序能走到局部钩子这一步,就说明你传的字典中的字段符合要求,这要记清楚,那么咱们在 取值就从clean_data中取就行了,clean_data里装的是符合要求的数据,是一个字典。 咱们能够从clean_data中取到相应的值再作一次逻辑处理,好比我写clean_name这个局部钩子, 我能够拿到name,对这个name进行一些操做,名字开头不能是数字,名字中不能有有什么字符,这 些等等,看你本身的需求,逻辑代码写好了,最后return name 就行了 全局钩子 全局钩子其实做用差很少的,每一个字段你能够进行局部钩子进行逻辑书写,这些处理完成以后,有须要的话, 你再进行全局处理,举个例子就大概能明白,你在写注册用户的时候,是否是有密码,确认密码,你能够进行 布局钩子处理,处理完毕是否是在进行判断,判断他们是否相等,相等的话,就存到数据库中,不相等就抛个 异常,对了对了,上面局部钩子忘记写异常,下面讲讲。 -----1、局部钩子,全局钩子所抛出异常的类型为ValidationError,它是在下面这行代码导入 from django.core.exceptions import ValidationError 2、局部钩子抛出的异常会添加到该字段中的错误信息中,也就是myform.errors.get(字段名)中 三、而全局钩子抛出的异常会添加到__all__中,myform.errors.get('__all__')中能够取到
做用:
1.手动对单表进行增,删,改,查,手动把orm操做获取的数据渲染到模块;(阶段1)
2.Form组件(类),自动生成标签(input,select),并对用户输入的数据作规则验证;(阶段2)
3.ModelForm顾名思义就Form和Django的Model数据库模型结合体,能够简单,方便地对数据库进行增长,编辑操做和验证标签的生成
使用ModelForm
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> {{ form_obj.as_p }} {#<p>姓名:{{form_obj.name }}</p>#} </body> </html>
class BSForm(forms.ModelForm): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) for filed in self.fields.values(): if not isinstance(filed, forms.BooleanField): filed.widget.attrs.update({'class': "form-control"}) class RegForm(BSForm): re_pwd = forms.CharField(widget=forms.PasswordInput, label='确认密码') class Meta: model = models.UserProfile fields='__all__' #获取所有的 exclude=['memo','is_active'] #删除不想要的 labels = { 'username': '用户名' #标签 } widgets = { 'password': forms.PasswordInput(attrs={'class': "form-control", 'k1': 'v1'}), } error_messages = { 'password': { 'required': '必填的' } } def clean(self): pwd = self.cleaned_data.get('password', '') re_pwd = self.cleaned_data.get('re_pwd', '') if pwd == re_pwd: return self.cleaned_data self.add_error('re_pwd', '两次密码不一致') raise ValidationError('两次密码不一直') def reg(request): form_obj=RegForm() if request.method =="POST": form_obj=RegForm(request.POST) if form_obj.is_valid(): # print(form_obj.cleaned_data) # form_obj.cleaned_data.pop('re_pwd') # models.UserProfile.objects.create(**form_obj.cleaned_data) form_obj.save() return redirect(reverse('login')) return render(request,'reg.html',{'form_obj':form_obj})
--MVC框架中包括一个重要的部分,就是ORM,它实现了数据模型与数据库的解耦,即数据模型的设计不须要依赖于特定的数据库,经过简单的配置就能够轻松更换数据库
--ORM是'对象-关系-映射'的简称 ,主要任务是:
*根据对象的类型生成表结构
*将对象,列表的操做,转换为sql语句
*将sql查询到的结果转换为对象,列表
--这极大地减轻了开发人员的工做量,不须要面对因数据库变动而致使的无效劳动
--Django中的模型包含存储数据的字段和约束,对应着数据库中惟一的表
1.在models.py中定义模型类,要求继承自models.Model 2.把应用加入settings.py文件的installed_app项 3.生成迁移文件 4.执行迁移生成表 5.使用模型类进行crud操做
在模型中定义属性,会生成表中的字段
django根据属性的类型肯定如下信息:
当前选择的数据库支持字段的类型
渲染管理表单时使用的默认html控件
在管理站点最低限度的验证
django会为表增长自动增加的主键列,每一个模型只能有一个主键列,若是使用选项设置某属性为主键列后,则django不会再生成默认的主键列
属性命名限制
不能是python的保留关键字
因为django的查询方式,不容许使用连续的下划线
定义属性时,须要字段类型 字段类型被定义在django.db.models.fields目录下,为了方便使用,被导入到django.db.models中 使用方式 导入from django.db import models 经过models.Field建立字段类型的对象,赋值给属性 对于重要数据都作逻辑删除,不作物理删除,实现方法是定义isDelete属性,类型为BooleanField,默认值为False 字段类型 AutoField:一个根据实际ID自动增加的IntegerField,一般不指定 若是不指定,一个主键字段将自动添加到模型中 BooleanField:true/false 字段,此字段的默认表单控制是CheckboxInput NullBooleanField:支持null、true、false三种值 CharField(max_length=字符长度):字符串,默认的表单样式是 TextInput TextField:大文本字段,通常超过4000使用,默认的表单控件是Textarea IntegerField:整数 DecimalField(max_digits=None, decimal_places=None):使用python的Decimal实例表示的十进制浮点数 DecimalField.max_digits:位数总数 DecimalField.decimal_places:小数点后的数字位数 FloatField:用Python的float实例来表示的浮点数 DateField[auto_now=False, auto_now_add=False]):使用Python的datetime.date实例表示的日期 参数DateField.auto_now:每次保存对象时,自动设置该字段为当前时间,用于"最后一次修改"的时间戳,它老是使用当前日期,默认为false 参数DateField.auto_now_add:当对象第一次被建立时自动设置当前时间,用于建立的时间戳,它老是使用当前日期,默认为false 该字段默认对应的表单控件是一个TextInput. 在管理员站点添加了一个JavaScript写的日历控件,和一个“Today"的快捷按钮,包含了一个额外的invalid_date错误消息键 auto_now_add, auto_now, and default 这些设置是相互排斥的,他们之间的任何组合将会发生错误的结果 TimeField:使用Python的datetime.time实例表示的时间,参数同DateField DateTimeField:使用Python的datetime.datetime实例表示的日期和时间,参数同DateField FileField:一个上传文件的字段 ImageField:继承了FileField的全部属性和方法,但对上传的对象进行校验,确保它是个有效的image 字段选项 经过字段选项,能够实现对字段的约束 在字段对象时经过关键字参数指定 null:若是为True,Django 将空值以NULL 存储到数据库中,默认值是 False blank:若是为True,则该字段容许为空白,默认值是 False 对比:null是数据库范畴的概念,blank是表单验证证范畴的 db_column:字段的名称,若是未指定,则使用属性的名称 db_index:若值为 True, 则在表中会为此字段建立索引 default:默认值 primary_key:若为 True, 则该字段会成为模型的主键字段 unique:若是为 True, 这个字段在表中必须有惟一值 关系 关系的类型包括 ForeignKey:一对多,将字段定义在多的端中 ManyToManyField:多对多,将字段定义在两端中 OneToOneField:一对一,将字段定义在任意一端中 能够维护递归的关联关系,使用'self'指定,详见“自关联” 用一访问多:对象.模型类小写_set
增: models.UserInfo.object.create(name=new_name) 删: models.UserInfo.object.get(id=xxx,None) models.delete() 改: obj = models.UserInfo.object.get(id=xx,None) obj = new_xxx obj.save() #至关于修改后提交数据 查 querylist=models.Entry.objects.all() print([e.title for e in querylist]) print([e.title for e in querylist]) entry = models.Entry.objects.get(id=?)
cookies是浏览器为web服务器存储的一个信息,每次浏览器从某个服务器请求页面时,都会自动带上之前收到的cookie.cookie保存在客户端,安全性较差,注意不要保存没敢信息.
--网络登陆
--购物车
def login(request): if request.method == 'GET': return render(request,'login2.html') if request.method == 'POST': u = request.POST.get('username') p = request.POST.get('pwd') dic = user_info.get(u) if not dic: return render(request,'login2.html') current_date = datetime.datetime.utcnow() current_date = current_date + datetime.timedelta(seconds=10) if dic['pwd'] == p: res = redirect('/myapp/index') # res.set_cookie('username',u,max_age=10) #对cookie设置了超时时间和安全设置 res.set_cookie('username',u,expires=current_date,httponly=True) # res.set_signed_cookie('username',u,salt="121221") return res else: return render(request,'login2.html')
详情页面,若是cookie 验证经过则进入index页面,不然刷新进入登陆页面
def auth(func): def inner(request,*args,**kwargs): v = request.COOKIES.get('username') if not v: return redirect('/myapp/login') return func(request,*args,**kwargs) return inner @auth def index(request): v = request.COOKIES.get('username') return render(request,'index2.html',{'current_user':v})
session就是保存在后台数据或者缓存中的一个键值对,一样的存储着用户信息,为更好的保护用户隐私,实际上是对前端cookie的一个升级的保护措施
当登陆成功后,会向后台数据库 与 前端 Cookie同时发放一段随机字符串,分别保存在后台的session中,前端 写到用户浏览器中,用户下次登陆时候 拿着浏览器存着的sessionID当作KEY去后台数据库中匹配进行验证登陆便可拿到用户相关信息,能够防止敏感信息直接暴露在浏览器上 做者:TianTianBaby223 连接:https://www.jianshu.com/p/a2d696364501 来源:简书 简书著做权归做者全部,任何形式的转载都请联系做者得到受权并注明出处。
Django下用session实现登陆验证
def sessionLogin(request): if request.method == "GET": return render(request,'sessionLogin.html') elif request.method == "POST": user = request.POST.get('user') pwd = request.POST.get('pwd') if user == 'root' and pwd =="123": #生成随机字符串 #写到用户浏览器 #保存到session中 #在随机字符串对应的字典中设置相关内容... request.session['username'] = user request.session['is_login'] = True if request.POST.get('rmb',None) == '1': request.session.set_expiry(10) return redirect('/myapp/sessionindex') else: return render(request, 'sessionLogin.html')
详情页逻辑
def sessionindex(request): #获取当前用户的随机字符串 #根据随机字符串获取对应信息 if request.session.get('is_login',None): return render(request,'sessionindex.html',{'username':request.session['username']}) else: return HttpResponse('get out')
定义:介于request(请求)与response(响应)处理之间的一道处理过程,相对比较轻量级,位于web服务端与url路由层之间
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware', #一些安全设置,好比xss脚本过滤
'django.contrib.sessions.middleware.SessionMiddleware',#session支持中间件,加入这个中间件,会在数据库中生成一个django_session的表。
'django.middleware.common.CommonMiddleware', #通用中间件,会处理一些url
'django.middleware.csrf.CsrfViewMiddleware', #跨域请求伪造中间件,加入这个中间件,在提交表单的时候会必须加入csrf_token,cookie中也会生成一个名叫csrftoken的值,也会在header中加入一个HTTP_X_CSRFTOKEN的值来放置CSRF攻击。
'django.contrib.auth.middleware.AuthenticationMiddleware', #用户受权中间件。他会在每一个HttpRequest对象到达view以前添加当前登陆用户的user属性,也就是你能够在view中经过request访问user。
'django.contrib.messages.middleware.MessageMiddleware',#消息中间件。展现一些后台信息给前端页面。若是须要用到消息,还须要在INSTALLED_APPS中添加django.contrib.message才能有效。若是不须要,能够把这两个都删除。
'django.middleware.clickjacking.XFrameOptionsMiddleware',#防止经过浏览器页面跨Frame出现clickjacking(欺骗点击)攻击出现。
'A_orm.middlewares.auth.AuthenticationMiddleware',
]
请求进来是自上而下,经过反射找到类,用for循环来执行,能够自定义中间件,但也要写入MIDDLEWAR中
1、process_request(self,request) #请求完执行 2、process_view(self, request, callback, callback_args, callback_kwargs) #若是有返回值,跳转到最后一个中间件,执行最后一个中间件的response方法,逐步返回 3、process_template_response(self,request,response) #默认不执行,只有在视图函数的返回对象中有render方法才会执行 4、process_exception(self, request, exception) #默认啥也不执行,在视图函数出现错误是才执行,返回错误信息 5、process_response(self, request, response) #响应执行
1、作IP限制 放在 中间件类的列表中,阻止某些IP访问了; 2、URL访问过滤 若是用户访问的是login视图(放过) 若是访问其余视图(须要检测是否是有session已经有了放行,没有返回login),这样就免得在 多个视图函数上写装饰器了! 3、缓存(还记得CDN吗?) 客户端请求来了,中间件去缓存看看有没有数据,有直接返回给用户,没有再去逻辑层 执行视图函数
执行顺序:
1.咱们要在app01文件下建立一个文件(middlewares)文件,在下面建立一个.py文件写入自定义中间件
2.在setting里面添加中间件,文件路径+功能
3.在views.py大家调用便可.
def index(request): print('1')
定义:用于框架执行操做时解耦,就是一些动做发生的时候,信号容许特定的发送者去提醒一些接受者
Model signals pre_init # django的model执行其构造方法前,自动触发 post_init # django的model执行其构造方法后,自动触发 pre_save # django的model对象保存前,自动触发 post_save # django的model对象保存后,自动触发 pre_delete # django的model对象删除前,自动触发 post_delete # django的model对象删除后,自动触发 m2m_changed # django的model中使用m2m字段操做第三张表(add,remove,clear)先后,自动触发 class_prepared # 程序启动时,检测已注册的app中modal类,对于每个类,自动触发 from django.db.models.signals import pre_init, post_init from django.db.models.signals import pre_save, post_save
Management signals pre_migrate # 执行migrate命令前,自动触发 post_migrate # 执行migrate命令后,自动触发
Request/response signals request_started # 请求到来前,自动触发 request_finished # 请求结束后,自动触发 got_request_exception # 请求异常后,自动触发 from django.core.signals import request_finished from django.core.signals import request_started
setting_changed # 使用test测试修改配置文件时,自动触发 template_rendered # 使用test测试渲染模板时,自动触发 from django.test.signals import setting_changed from django.test.signals import template_rendered
connection_created # 建立数据库链接时,自动触发 from django.db.backends.signals import connection_created