django的详细介绍
django知识点总结:
目录 django知识点总结:知识点准备一、知识准备:二、http协议的四大特性三、django的安装四 Django静态文件配置五 Django请求生命周期完整版登录功能知识准备二、ORM三、路由层(url):三、视图层1 虚拟环境2.1补充:四、模板层总结五、模型层基础总结补充:inclusion_tag补充事务:补充choice:补充defer和only(数据库优化)六、组件一、Django与Ajax二、分页器组件三、forms组件四、cookie组件五、sessioncbv+装饰器六、中间件中间件回顾七、auth组件今日内容:博客项目
知识点准备
一、知识准备:
请求格式:b‘HTTP/1.1 200 ok\r\n\r\nstr’
请求方式/协议及版本号 请求头
响应状态码:
响应:
响应码
二、http协议的四大特性
基于TCP/IP协议之上的应用层协议
基于请求 响应模式的协议
无状态:每次连接之间没有关系
无连接:发送一次返回了立马结束
三、django的安装
(1)下载Django
方式一:在命令行输入:pip3 install django
pip install django==1.11.9 -i http://pypi.hustunique.org/simple 指定版本号,指定国内镜像
方式二:用pycharm安装
方式三:用pycharm的Terminal的命令行安装
(2)创建一个django project
django-admin.py startproject mysite
当前目录下会生成mysite的工程,目录结构如下:
- manage.py ----- Django项目里面的工具,通过它可以调用django shell和数据库等。
- settings.py ---- 包含了项目的默认设置,包括数据库信息,调试标志以及其他一些工作的变量。
- urls.py ----- 负责把URL模式映射到应用程序。
(3)在mysite目录下创建应用
python manage.py startapp blog
(4)、启动django项目
python manage.py runserver 8001
四 Django静态文件配置
新建一个目录叫:static,我们的css文件,js文件,图片文件都放在这下面
STATIC_URL = '/static/'
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'static'),
]
五 Django请求生命周期
小例子:
完整版登录功能
1 login.html
***重点***1 action:提交到后台的地址三种写法:
1 http://127.0.0.1:8000/login
2 /login/ 推荐用
3 空
2 method post方式
3 <input type="submit" value="提交">或<button></button>
type不可以是button
<form action="http://127.0.0.1:8000/login" method="post">
<p>用户名:<input type="text" name="name" class="form-control"></p>
<p >
密码:<input type="password" name="pwd" class="form-control">
</p>
<input type="submit" value="提交">
</form>
2 视图层:
1 request.method ----前台提交过来请求的方式
2 request.POST(相当于字典)----post形式提交过来的数据,(http请求报文的请求体重)
3 request.POST.get('name') ----推荐用get取值(取出列表最后一个值)
4 request.POST.getlist('name')-----取出列表所有的值_
5 前台get方式提交的数据,从request.GET字典里取
3 链接数据库(防止注入,推荐以下写法)
cur.execute('select * from user where name=%s and password=%s ',[name,pwd])
知识准备
5 get请求和post请求
get:获取数据,页面,携带数据是不重要的数据(数据量有大小限制)
post:往后台提交数据
6 新手三件套总结
1 render--返回页面
默认会去templates里找,注意路径
2 redirect--重定向
3 HttpResponse
本质:都是返回HttpResponse的对象
7 pycharm连接mysql
二、ORM
1 ORM即Object Relational Mapping,全称对象关系映射。
优点:
1 不用写sql,不会sql的人也可以写程序
2 开发效率高
缺点:
1 可能sql的效率低
3 如何使用:
如果连接mysql:在setting里配置:
'default': {
'ENGINE': 'django.db.backends.mysql',
'HOST': '127.0.0.1',
'PORT': 3306,
'USER': 'root',
'PASSWORD': 'admin',
'NAME': 'lqz',
}
在app下的init.py里写:
import pymysql
pymysql.install_as_MySQLdb()
4 django-orm:
1 不能创建数据库(需要手动创建数据库)
2 可以创建数据表
3 可以创建字段
5 数据库迁移
1 python3 manage.py makemigrations ----记录一下数据库的变化
2 python3 manage.py migrate ----将变化同步到数据库中
具体内容:
1 orm介绍
1 tools--->Run manage.py Task
python3 manage.py makemigrations
只需要敲命令:makemigrations(记录数据库的修改记录)
python3 manage.py migrate
只需要敲命令:migrate(把数据同步到数据库)
2 orm能干和不能干的事
1 能创建数据表,新增,删除字段
2 不能创建数据库
3 orm增加字段:(注意数据库迁移命令2条)
注意:后来增加的字段,需要有默认值
phone=models.CharField(max_length=64,default='120')
4 删除字段
注释掉字段,执行数据库迁移命令
5 修改数据
直接修改字段,执行数据库迁移命令
6 user的增删改查
重点*:
1 单表查询所有用户:models.User.objects.all()
得到的是 queryset对象(当成列表),列表里面,一个一个的对象[user1,user2]
2 render(request, 'userlist.html', {'user_list': ret})
3 模板里: {% for user in user_list %}
要循环的内容
{{user.name}}
{% endfor%}
4 get请求携带参数:
http://127.0.0.1:8000/deleteuser/?id=1
后台取值:request.GET.get('id')
request.GET['id']
5 orm删除记录 models.User.objects.filter(id=id).delete()
返回值:影响的行数
6 前台post提交的数据取值:name=request.POST.get('name')
7 orm保存:
两种方式:
1 user=models.User.objects.create(name=name,password=pwd,address=addr)
2 user=models.User(name=name,password=pwd,address=addr)
user.save()
8 orm查询单条数据:user=models.User.objects.filter(id=id).first()
9 orm的修改 models.User.objects.filter(id=id).update(name=name,password=pwd,address=addr)
三、路由层(url):
1、简单配置
url(r‘^admin/’,admin.site.urls),
第一个参数是正则表达式(如果要精确匹配:'^publish/$')
第二个参数是视图函数(不要加括号)
url(r'^admin/', admin.site.urls),
2 无名分组
按位置传参
分组之后,会把分组出来的数据,当位置参数,传到视图函数,所以,视图函数需要定义形参
url(r'^publish/([0-9]{4})/([0-9]{2})$', views.publish),
def publish(request,*args): 视图函数可以这样接收
3 有名分组
按关键字传参
有名分组之后,会把分组出来的数据,当关键字参数,传到视图函数,所以,视图函数需要定义形参,形参名字要跟分组的名字对应,与顺序无关
url(r'^publish/(?P
def publish(request, mounth,year):
*有名分组和无名分组,不要混用
4 反向解析
先命一个名:
1 无参数:url(r'^publishadd133/$', views.publishadd,name='ddd'),
2 无名分组:url(r'^publishadd/([0-9]{4})/([0-9]{2})/$', views.publishadd,name='ddd'),
3 有名分组:url(r'^publishadd/(?P
在模板层:
1 无参数:{% url 'ddd' %}
2 无名分组的:{% url 'ddd' 2018 12 %}
3 有名分组:{% url 'ddd' 2018 12 %} 还可以 {% url 'ddd' year=2018 mounth=12 %}
在视图层:
from django.shortcuts import reverse
在视图函数里:
无参数:url=reverse('ddd')
无名分组:url=reverse('ddd',args=(2018,12,))
有名分组:url=reverse('ddd',args=(2018,12,)) 还可以 url=reverse('ddd',kwargs= {'year':2018,'mounth':12})
5 路由分发
1 在不同的app里创建urls.py
2 在总路由
from django.conf.urls import include
url(r'^blog/',include('blog.urls')),
url(r'^app01/',include('app01.urls')),
3 在不同的app的urls里配置路由关系
重点总路由,不能加结束符$
6 名称空间
url(r'^blog/',include('blog.urls',namespace='blog')),
子路由:url(r'^publish/$', views.publish,name='test'),
反向解析:
视图层:url = reverse('blog:test')
模板层:{% url 'app01:test'%}
一般不要用
子路由:url(r'^publish/$', views.publish,name='app01_test'),
7 伪静态
路由:url(r'^book/(?P
访问:http://127.0.0.1:8000/book/4.html
三、视图层
1 虚拟环境
1 用pychanrm创建--->files-->newproject--->选择虚拟环境
2 settings-->project创建
3 用命令行创建,详见https://www.cnblogs.com/liuqingzheng/p/9508851.html
2 django 2.0和django 1.0 路由层区别(*url,re_path分组分出来的数据,是字符串)
re_path:跟1.0的url用法相同
path:传的路径,是准确路径
5个转换器-->path('test/path:year', views.re_test),
str,匹配除了路径分隔符(/)之外的非空字符串,这是默认的形式
int,匹配正整数,包含0。
slug,匹配字母、数字以及横杠、下划线组成的字符串。
uuid,匹配格式化的uuid,如 075194d3-6885-417e-a8a8-6c931e272f00。
path,匹配任何非空字符串,包含了路径分隔符(/)(不能用?)
自定义转换器
1 定义一个类:
class MyCon:
写一个正则表达式
regex = '[0-9]{4}'
匹配出來的数据,会传到这里,retrun回去的,会被视图函数接收
def to_python(self, value):
return int(value)
反向解析用的
def to_url(self, value):
return '%04d' % value
2 from django.urls import register_converter
register_converter(MyCon,'yyy')
3 path('test/yyy:year', views.re_test,name='test'),
2.1补充:
为假,不会加反斜杠
APPEND_SLASH=False
3 视图层之HttpRequest对象
前台Post传过来的数据,包装到POST字典中
request.POST
前台浏览器窗口里携带的数据,包装到GET字典中
request.GET
前台请求的方式
request.method
post提交的数据,body体的内容,前台会封装成:name=lqz&age=18&sex=1
request.body
取出请求的路径,取不到数据部分
print(request.path)
取出请求的路径,能取到数据部分
print(request.get_full_path())
print(request.META)
4 视图层之HttpResponse对象
三件套:render,HttpResponse,redirect
render函数:
temp=Template('
{{ user }}
')con=Context({'user':'lqz'})
ret=temp.render(con)
print(ret)
return render(request,'index.html')
return HttpResponse(ret)
5 视图层之JsonResponse对象
导入:from django.http import JsonResponse
视图函数中:
def test(request):
import json
dic={'name':'lqz','age':18}
ll = ['name', 'age']
把字典转换成json格式,返回到前台
return HttpResponse(json.dumps(dic))
把列表转换成json格式,返回到前台
return HttpResponse(json.dumps(ll))
把字典转换成json格式,返回到前台
return JsonResponse(dic)
报错,默认不支持列表形式
return JsonResponse(ll)
支持列表形式
return JsonResponse(ll,safe=False)
6 CBV和FBV
基于类的视图
1 路由层:url(r'^test/', views.Test.as_view()),
2 视图层
导入:from django.views import View
写一个类:
class Test(View):
def get(self, request):#一定要传request对象
return HttpResponse('get-test')
def post(self, request):
return HttpResponse('post-test')
基于函数的视图
7 简单文件上传
前端:
后台:
def fileupload(request):
if request.method=='GET':
return render(request,'fileupload.html')
if request.method=='POST':
FILES
print(request.FILES)
print(type(request.FILES.get('myfile')))
从字典里根据名字,把文件取出来
myfile=request.FILES.get('myfile')
from django.core.files.uploadedfile import InMemoryUploadedFile
文件名字
name=myfile.name
打开文件,把上传过来的文件存到本地
with open(name,'wb') as f:
for line in myfile.chunks():
for line in myfile:
f.write(line)
return HttpResponse('ok')
补充:*编码方式multipart/form-data或者:application/x-www-form-urlencoded传的数据,都可以从POST中取出来
四、模板层
昨日回顾:
1 虚拟环境
1 pycharm里创建
2 用命令串讲
2 视图层:
1 Request对象---GET,POST,method,body,FILES,META,path(只是路径),get_full_path(拿到全路径,带数据),
2 HttpResponse对象--->render,redirect,HttpResponse,JsonResponse(返回json格式)
3 反向解析--->在视图层:本质为了去除地址,重定向来用;在模板层:取出地址,为了发请求来用
4 JsonResponse:JsonResponse(dic,json_dumps_params={'ensure_ascii':False})---中文显示编码问题
5 FBV和CBV
from django.views import View
class Test(View)
def get(self,request):
pass
def post(self,request):
pass
6 django 2.0的path,re_path
1 re_path跟原来的url一毛一样
2 path:准确路径
3 path 内置转换器:5个 int,str,path....用法:int:year
4 自定义转换器:
yyy:year
7 文件上传 1 html页面上指定编码格式:enctype="multipart/form-data"
2 视图层:request.FILES(字典),可以根据名字,把文件取出来
-myfile=request.FILES.get('文件名字')--->得到文件对象
3 for循环文件对象,保存到本地,文件名字:myfile.name
今日内容:(模板层)
1 模版语法之变量:详见源码
{{ 变量 }}:**重要**{#相当于print了该变量#}
深度查询---->统一都用句点符 .
2 模版之过滤器
-语法:{{第一个参数|过滤器名字:第二个参数}}
常用过滤器:(详细用法见源码)
-length
-default
-slice
-date
-filesizeformat
-truncatechars
-truncatewords
-safe
-add
3 模版之标签
-{% 标签 %}
for:forloop:对象(里面有好多东西:parentloop,last,first,counter....)忘记的话,自己打印一下
empty:被循环的对象是空,才走它
for循环可以嵌套,也可以用if
if:
{% if forloop.first %}
<p>第一次的我 </p>
{% elif forloop.last %}
<p>最后的我 </p>
{% else %}
<p>{{ foo }}</p>吧
{% endif %}
with:重命名,应用在变量名过长
**都要有结束**
4 自定义标签和过滤器
***标签不能用在if判断,过滤器,可以用在if判断
-自定义过滤器
1 先app是不是已经在setting中注册
2 在app下创建一个templatetags(名字不能变***)的文件夹(模块)
3 在模块下创建一个py文件,名字随意:mytag.py
4
第一步,导入template
from django.template import Library
第二步,定义一个叫register的变量=template.Library()
register = Library()
5 写一个函数,用@register.filter(name='yyy')装饰一下(可以指定别名)
def str_add(str1, str2): #一定要有返回值
# 业务逻辑很复杂
return str1 + str2
6 在模板里:(新定定义的标签,过滤器,都要重启程序)
{% load mytag %}
{{'lqz'|str_add:'nb'}}
自定义标签:
1-4:前4步,根过滤器的定义完全一样67
5 只是装饰器不一样
@register.simple_tag()
def add_nb(value):
return value+'nb'
6 在模板里:(多个参数,以空格区分)
{% load mytag %}
{% add_nb 'lqz'%}
总结
1 模板之变量---{{ }}
-支持数字,字符串,布尔类型,列表,字典---相当于对它进行了打印
-函数--->相当于加括号运行(不能传参数)
-对象--->内存地址,(如果重写str方法,打印的就是返回的内容)
2 过滤器
-length---计算长度
-default----设默认值
-filesizeformat---把数字转成文件大小格式
-截断字符---最少是三
-截断单词
-data----格式化日期类型
-add-----数字,字符串相加
-slice----切片,首,尾,步长 '1👎2'
-safe-----把前端代码渲染到页面,而不是直接显示
3 标签
-for --用法跟python一样
-if --用法跟python一样
-with --相当于取别名
4 自定义标签
-1 在app下创建一个模块,名字必须叫templatetags
-2 创建任意一个py文件,my_tags.py
-3 导入:from django.template import Library
-4 注册:register=Library()
-5 写一个函数,用register.simple_tag(name=可以写一个别名),装饰一下
-6 使用(重启)
-7 在模板里:{%load my_tags%}
-8 {% 函数名字或者别名 %},传参,用空格分割
5 自定义过滤器
-1 在app下创建一个模块,名字必须叫templatetags
-2 创建任意一个py文件,my_tags.py
-3 导入:from django.template import Library
-4 注册:register=Library()
-5 写一个函数,用register.filter(name=可以写一个别名),装饰一下
-6 使用(重启)
-7 在模板里:{%load my_tags%}
-8 {{ 函数名字或者别名 }},传参,最多传两个参数{{'参数一'|过滤器名字:'参数二'}}
6 过滤器可以用在if判断中,标签不能
五、模型层
1 模版导入-->写了一个好看的组件,可以复用,
1 写一个模板
2 在模板中:{% include '模板的名字'%}
2 模板的继承
1 写一个母版,留一个可扩展的区域(盒子),可以留多个盒子(留的越多,可扩展性越高)
{%block 名字%}
可以写内容
{%endblock%}
2 在子模板中使用:
{%block 名字%}
子模板的内容
{%endblock 名字%}
3 静态文件相关
1 写死静态文件:<link rel="stylesheet" href="/static/css/mycss.css">
2 使用 static标签函数:
-{%load static%}
#static返回值,会拼上传参的路径
-{% static "传参"%}
3 使用get_static_prefix 标签
-{%load static%}
#get_static_prefix返回值是:静态文件的地址,相当于/static/
-{% get_static_prefix %}css/mycss.css
4 单表操作;
-数据迁移命令:
-python3 manage.py makemigrations --->只是对变化做一个记录,记录文件在app的migrations
-python3 manage.py migrate ---->把更改提交到数据库
-python3 manage.py showmigrations ---->查看那个没有提交到数据库
-查询api
<1> all(): 查询所有结果
<2> filter(**kwargs): 它包含了与所给筛选条件相匹配的对象
<3> get(**kwargs): 返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误。
<4> exclude(**kwargs): 它包含了与所给筛选条件不匹配的对象
<5> order_by(*field): 对查询结果排序('-id')
<6> reverse(): 对查询结果反向排序
<8> count(): 返回数据库中匹配查询(QuerySet)的对象数量。
<9> first(): 返回第一条记录
<10> last(): 返回最后一条记录
<11> exists(): 如果QuerySet包含数据,就返回True,否则返回False
<12> values(*field): 返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列
model的实例化对象,而是一个可迭代的字典序列
<13> values_list(*field): 它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列
<14> distinct(): 从返回结果中剔除重复纪录
-基于双下划线的模糊查询
Book.objects.filter(price__in=[100,200,300])
Book.objects.filter(price__gt=100)
Book.objects.filter(price__lt=100)
Book.objects.filter(price__gte=100)
Book.objects.filter(price__lte=100)
Book.objects.filter(price__range=[100,200])
Book.objects.filter(title__contains="python")
Book.objects.filter(title__icontains="python")
Book.objects.filter(title__startswith="py")
Book.objects.filter(pub_date__year=2012)
1 创建多表模型(详情见代码)
用了OneToOneField和ForeignKey,模型表的字段,后面会自定加_id
ManyToManyField会自动创建第三张表
*****重点
一对一的关系:OneToOneField
一对多的关系:ForeignKey
多对多的关系:ManyToManyField
2 添加表记录
1 一对多新增
-两种方式:
-publish=对象
-publish_id=id
2 一对多删除:同单表删除
3 一对多修改:两种方式,可以传对象,可以传id
4 一对一跟一对多一样
5 多对多:
-add ----->可以传对象,可以传id,可以传多个
-remove ----->可以传对象,可以传id,可以传多个
-clear ---->没有参数
-set ----->跟上面不一样,必须传列表,列表里面可以是对象,可以是id
3 基于对象的跨表查询
1 一对一
正向:正向查询按字段
反向:反向查询按表名小写
2 一对多
正向:正向查询按字段
反向:反向按表名小写_set.all()
3 多对多
正向:正向查询按字段
反向查询:反向按表名小写_set.all()
4基于对象的查询,多次查询(子查询)
4 基于双下划线的跨表查询
-连表查询
-一对一双下划线查询
-正向:按字段,跨表可以在filter,也可以在values中
-反向:按表名小写,跨表可以在filter,也可以在values中
5基于双下划线的跨表查询
1 套路一样,用__跨表
-一对多
-多对多
2 聚合查询
-聚合函数
from django.db.models import Avg,Count,Max,Min,Sum
计算所有图书的平均价格
ret=Book.objects.all().aggregate(Avg('price'))
print(ret)
3 分组查询
终极总结:
values在前,表示group by,在后,表示取值
filter在前,表示过滤(where),在后,表示having(对分组之后的结果再进行过滤)
4 F查询与Q查询
-F为了字段=后面的值,不能放字段,所以用F函数包裹一下就可以了
-Q为了构造与&,或|,非~的关系
5 常用字段:必须记住,非常用字段,了解即可
6 orm字段参数:
-null 可以为空
-unique 唯一性约束
-default 默认值
-db_index 为该字段建索引
-只给日期类型和时间类型用
-auto_now_add 新增数据时,默认把当前时间存入
-auto_now 修改的时候,默认把当前时间存入
7 关系字段
ForeignKey
-to 关联哪个表
-to_field 关联的字段
-related_name 反向操作时,使用的字段名,用于代替原反向查询时的'表名_set'。(一般不要用)
-related_query_name :基于双下划线的反向查询之前按表名小写(一般不要用)
-on_delete:models.CASCADE,models.SET_NULL
-db_constraint:db_constraint=False代表,不做外键关联
1 模板导入
-写一个模板
-{%include '模板名字'%}
2 母版继承
-写一个母版(留几个盒子),名字叫XX
-{% block 名字 %}
{%endblock%}
-使用:继承母版
-{%extends 'XX'%}
-重写盒子(多个盒子,位置无关)
-{% block 名字 %}
写内容
{%endblock%}
3 静态文件相关
方式一
-先创建一个static的文件夹
-settings配置静态文件
-STATICFILES_DIRS=[
os.path.join(BASE_DIR,'static')
]
- <link rel="stylesheet" href="/static/utils/bootstrap-3.3.7-dist/css/bootstrap.css">
-<script src="/static/utils/bootstrap-3.3.7-dist/js/bootstrap.js"></script>
方式二(动态)
-使用:{%load static%}
-<script src="{% static 'utils/bootstrap-3.3.7-dist/js/bootstrap.js'%}"></script>
方式三:
-使用:{%load static%}
-<script src="{% get_static_prefix %}css/mycss.css"></script>
4 单表操作:
-mysql数据库:settings里配置
'default': {
# key值必须都是大写
'ENGINE': 'django.db.backends.mysql',
'NAME': 'day76',
'HOST':'127.0.0.1',
'PORT':3306,
'USER':'root',
'PASSWORD':'admin',
}
-在init文件中:
import pymysql
pymysql.install_as_MySQLdb()
-在models中,写类,写类的属性
#自增,int,主键
id = models.AutoField(primary_key=True)
#varchar,长度32
name = models.CharField(max_length=32)
#Decimal 长度5,小数位2位
price = models.DecimalField(max_digits=5, decimal_places=2)
#日期类型,可以为空
create_data=models.DateField(null=True)
-数据库迁移:
python3 manage.py makemigrations --->只是对数据变更,做记录
python3 manage.py migrate ---->把变更,同步到数据库
-新增表,删除表,新增字段,删除字段---->执行数据库迁移的两条命令就可以了
-单表增:
-两种方式
-单表修改:
-先查询出来,然后update(queryset对象的方法)
-对象要更新,用save方法
-单表删除:
-先查询出来,然后delete(queryset对象和模型对象的方法)
*****用queryset删除,修改的时候,一定要注意,数据是几条
-删除数据表中所有数据:Book.objece.all().delete()
-单表查询
-all()
-filter(**kwargs)
-get(**kwargs) 有且只有一条数据
-exclude(**kwargs)
-order_by(*field)
-reverse()
-count()
-first()
-last()
-exists()
-values(*field)
-values_list(*field)
-distinct()
-单表基于双下划线模糊查询
Book.objects.filter(price__in=[100,200,300])
Book.objects.filter(price__gt=100)
Book.objects.filter(price__lt=100)
Book.objects.filter(price__gte=100)
Book.objects.filter(price__lte=100)
Book.objects.filter(price__range=[100,200])
Book.objects.filter(title__contains="python")---->%python%
Book.objects.filter(title__endswith="py")----->%py
Book.objects.filter(title__startswith="py")---->py%
Book.objects.filter(title__icontains="python")--->忽略大小写
Book.objects.filter(pub_date__year=2012,pub_date__month=12)
5 表模型创建(约束,外键管理--->不写脏数据)
-OneToOneField ---一对一
-ForeignKey----一对多
-级联删除CASCADE
-设置为空:SET_NULL
-什么都不做:DO_NOTHING
ForeignKey(to=Publish, to_field='id',on_delete=models.CASCADE)
-ManyToManyField ------>多对多(自动创建第三张表)
-AutoField(primary_key=True)
-CharField
-EmailField
6 基于对象的多表查询
-子查询(多次查询)
-正向 ---->关联字段在那个表,从那个表往外查
-反向 ---->关联字段不在那个表,从那个表往外查
-一对一
-正向查询:按字段
-反向查询:按表名小写
-一对多
-正向查询:按字段
-反向查询:按表名小写_set.all()------>queryset对象
-多对多
-正向查询:按字段.all()
-反向查询:按表名小写_set.all()------>queryset对象
7 基于双下划线的一对一查询
-正向按字段
-反向按表名小写
-查询lqz的手机号
Author.objects.filter(name='lqz').values('authordetail__phone')
AuthorDetail.object.filter(author__name='lqz').values('phone')
8 查看orm转换的sql
-queryset.query
-日志
9 增删改
增:
-一对一
-可以传对象,可以传id
-一对多
-可以传对象,可以传id
-多对多:
-add() --->可以传对象,可以传id,可以传多个
删:
-多对多
-remove() --->可以传对象,可以传id,可以传多个
-clear() --->全部清空
改:
-多对多
-set() ---->先清空,再添加,传参,只能传列表
10 基于双下划线的跨表查询
一对一
-查询egon的家庭地址 -Author.objeces.all().filter(name='egon').values('authordetail__addr')
-AuthorDetail.objeces.all().filter(author__name='egon').values('addr)
一对多:
-查询主键为1的书籍的出版社所在的城市
-Book.objeces.filter(pk=1).values('publish__addr')
-Publish.objeces.filter(book__pk=1).values('addr')
多对多
-查询金平梅所有作者的名字以及手机号
-Book.objeces.filter(name='金平梅').values('authors__name','authors__authordetail__phone')
-Author.objeces.filter(book__name='金平梅').values('name','authordetail__phone')
连续跨表:
-跟上面一样
-效率问题:基于哪个表,效率都一样
11 聚合
-聚合函数
-from django.db.models import Count,Avg,Min,Max,Sum
-查询所有图书的总价格
-Book.objeces.all().aggregate(c=Sum('price'))
-查询结果不是queryset对象了,不能再继续点了
-aggregate可以传多个
12 分组查询
-统计每一本书作者个数
-Book.objeces.all().values('pk').annotate(c=Count('authors__pk')).values('name','c')
-Book.objeces.annotate(c=Count('authors')).values('name','c')
-统计以红开头,作者个数大于一的书
-Book.objeces.all().filter(name__startswith='红').annotate(c=Count('authors')).filter(c__gt=1).values('name','c')
-*********终极总结:
-values 在前,表示group by哪个字段,在后,表示取值
-filter在前,表示where(先过滤),在后,表示having
13 F函数
-为了等号(=)不能直接传字段,用F函数包裹一下,就可以传了
-查询评论数大于阅读数的所有书
-from django.db.models import F
-Book.objeces.all().filter(commit_num__gt=F('reat_num'))
14 Q函数
-表示与(&)或(|)非(~)的关系
-出版日期在2016或者2017并且名字包含python的所有书
-Book.objeces.filter((Q(pub_date__year=2016)|Q(pub_date__year=2017))&Q(name__icontains='python'))
-Book.objeces.filter(Q(pub_date__year=2016)|Q(pub_date__year=2017),name__icontains='python')
-如果出现Q 对象,它必须位于所有关键字参数的前面
15 常用和非常用字段
-AutoField ---->一个类中(表中)最多有一个
-models.CharField(max_length=32,db_index=True)
-models.DecimalField(max_digits=5, decimal_places=2)
-IntegerField(default=0)
-DateField()
-auto_now ----->修改的时候,会把当前时间更新上
-auto_now_add --->新增数据时,会把当前时间记录上
16 字段参数
-null
-default
-unique
-db_index
-db_constraint
-on_delete --->2.0以后,这个字段必须传
-related_name ---->基于对象反向查询,用于替换表名小写_set
-related_query_name ---->基于双下划线反向查询,用于替换表名小写
17 元信息
-在模型类中加入一个类
class Meta:
-指定表名
-指定联合唯一
-指定联合索引
基础总结
回顾:
1 HTTP协议:(重点)
-请求
-请求首行
-GET /index HTTP/1.1
-请求头部(在django框架中,可以从META中取出来)
-key:value------>\r\n分割
-请求体(post请求发的数据) -----\r\n\r\n
-往后台传数据的时候,有编码方式(urlencoded,form-data,json/text)
-默认urlencoded---->name=lqz&name=18---->从POST中取出
-form-data---上传文件,数据在body体中的格式---->也从POST中取出
-json---->从POST中取不出来,只能从body中取出,然后反序列化
-响应
-响应首行(用空格区分)
-HTTP/1.1 200 OK ---\r\n
-响应头
-key:value
-响应体
-html/css/js代码
2 web框架
-django:大而全
-flask:轻量级,第三方的插件
-tornado:异步非阻塞
-wsgi:Web Server Gateway Interface web服务网关接口---是一个协议
-django测试阶段用的:wsgiref
import socket
def server_run():
soc = socket.socket()
soc.bind(('127.0.0.1', 8008))
soc.listen(5)
while True:
conn, addr = soc.accept()
recv_data = conn.recv(1024)
----->django框架
路由层
模板层
模型层
conn.send(('HTTP/1.1 200 OK\r\n\r\n%s'%data).encode('utf-8'))
conn.close()
3 django框架所在位置:
from wsgiref.simple_server import make_server
def mya(environ, start_response):
# print(environ)
start_response('200 OK', [('Content-Type', 'text/html')])
return [b'404']
class Test():
pass
test=Test()
if __name__ == '__main__':
myserver = make_server('127.0.0.1', 8011, test)
print('监听8010')
myserver.serve_forever()
4 django简介
-pip3 install django==1.11.09 -i 指定国内源
-安装成功后,会在script文件夹下多django-admin.exe
-用来创建django项目
-django-admin startproject 项目名字(到指定文件夹下)
-cd到项目目录下,可以创建app,可以运行项目,可以数据库迁移
-创建app:python3 manage.py startapp app的名字
-运行项目app:python3 manage.py runserver
-数据库迁移1:python3 manage.py makemigrations
-数据库迁移2:python3 manage.py migrate
5 mvc和mtv
-django 是mtv模式:
-M:model ---->模型
-T:Template --->模板
-V:view ---->视图
-mvc模式:
-M:model---->模型,数据库相关
-v:view----->模板---->页面相关
-C:controller--->控制器:url+view
本质上:MTV就是MVC
6 Django请求生命周期
详见博客
7 路由层
一 Django中路由的作用
-根据客户请求的路径,分发到不同的视图函数
二 简单的路由配置
-url('正则',函数,默认值,name)
url(r'^author_update/', author.author_update,{'id':1}),
三 有名分组,无名分组
-利用正则分组:
-有名分组:(?P<名字>\d+),分出的名字,会以关键字参数的形式,传到视图函数
-无名分组:(\d+)分出的名字,会以位置参数的形式,传到视图函数
四 路由分发
- url(r'^author_update/', include('子路由的路径')),
-可以传子路由的路径字符串----推荐这种
-可以传子路由的py文件
五 反向解析
-url(r'^author_update/', author.author_update,name='test'),
-视图函数重定向,或者模板中写死了路径
-可以用反向解析来动态生成路径
-视图层:(有参数)
-url=reverse('test',args=(参数一,参数二,))
-模板层:(有参数)
{%url 'test' 参数一 参数二%}
六 名称空间
-路径重命名,可能会重复,反向解析,就会出问题
-指定名称空间
-url(r'^author_update/',include('子路由路径',namespace='app01')),
-reverse('app01:test')
七 django2.0版的path
-re_path根url一样
-path是准确路径
-5个转换器:int,str,slug,path,uuid
-自定义转换器
class Test:
regex='正则'
def to_python(self,value):
逻辑处理
return value
def to_url(self,value)
return '%04d'%value
-使用:
-register_converter(converters.FourDigitYearConverter, 'yyyy')
-<yyy:year>
八 伪静态:
8 视图层
-请求
-request对象:POST,GET(post提交数据,浏览器地址栏,也可以携带参数),method(大写),body(post提交的所有数据),path(路径),get_full_paht()-->(全路径,包含数据),FILES(前台传过来的文件,它是一个字典),META
-响应:
-render,HttpResponse,redirect
-JsonResponse-->往前台返回一个json格式数据(本质:继承了HttpResponse,封装了json)
-不能转换列表,想转换,safe=False
-编码方式
-cbv和fbv
基于类的视图
-路由:url(r'^test/', views.Test.as_view()),
-视图:
class Test(View):
def dispatch(self, request, *args, **kwargs):
# 加点东西
# request=request.POST
response=super().dispatch(request, *args, **kwargs)
# 加点东西
return response
def get(self,request):
return HttpResponse('get')
基于函数的视图
9 模版层
一 模版简介
渲染页面
二 模版语法之变量
-{{ 变量 }}
-{{深度查询用.}}
三 模版之过滤器
-自带过滤器
{{ 参数|过滤器名字:参数 }}
-date
-add
-length
-upper
-lower
-可以自定义过滤器
四 模版之标签(都要有结束)
-{% for %}
-循环字典:(在模板里,方法不能加括号)
{% for key,value in 字典.items%}
-forloop对象:parentloop,last,first,count,count0,revcountcount,revcount0
-{% if %}
-跟python if判断一样
-可以嵌套在for循环中
-{% elif%}
-{% else%}
-{% with%}
-重命名
五 自定义标签和过滤器
-先注册app
-在app下创建一个templatetags的模块
-在模块下新建一个py文件
-from django.template import Library
-register=Library()------>名字必须叫register
-标签:
-用装饰器装饰 @register.simple_tag
-过滤器
-用装饰器装饰 @register.filter
-过滤器最多只能传两个参数,标签可以传多个
-在模板中使用:
-{% load py文件名%}
-{{参数|自定义的过滤器:参数}}----->过滤器
-{% 自定义的标签名 参数一 参数二 %}----->标签
补充:inclusion_tag
-先注册app
-在app下创建一个templatetags的模块
-在模块下新建一个py文件
-from django.template import Library
-register=Library()------>名字必须叫register
-使用装饰器:@register.inclusion_tag('test.html')
-写个函数my_inclusion,返回字典
-模板里就能取到字典,渲染模板
-使用:
在模板中:{%load py文件名%}
{% my_inclusion 参数%}
六 模版导入和继承
-在模板中
-{% include '模板的名字'%}----->不要再以html开头,结尾了
-继承
-写一个母版,留几个盒子
-{%block 名字%}
{%endblock%}
-其他模板继承该母版,扩写盒子
{%extends '母版名字'%}
{%block 名字%}
写内容
{%endblock%}
-block.super--->可以显式盒子中原来有的东西
-多个盒子,跟写的位置无关
七 静态文件相关
- 基本配置<link rel="stylesheet" href="/static/mycss.css">
-static配置:
-{%load static%}
-{% static 'mycss.css'%}
-<link rel="stylesheet" href="{% static 'mycss.css'%}">
-get_static_prefix配置
-{% load static %}
-<link rel="stylesheet" href="{% get_static_prefix %}mycss.css">
10 模型层
-单表操作
-增:两种方式,create,对象.save()
-删:两种方式:queryset,对象都要删除方法
-修改:queryset的update方法,对象修改--->没有update,用save
-查:
-查询api
-模糊查询:基于双下划线
-多表操作
-增加:
一对一:authordetail=对象----authordetail_id=id
一对多:可以传对象,可以传id
多对多:
-add,remove,
-*args--可以传对象,可以传id
-clear()清空所有
-set
-传一个可迭代对象(可以传对象,可以传id)
-删除:如果设置了级联删除,就会级联删除
-查询
-正向:关联字段在那个表,从哪个表往外查,是正向
-反向:反过来
-基于对象
-正向按字段
-反向
-一对一 :表名小写
-其他:表名小写_set
-子查询,多条查询
-基于双下划线
-核心:__连表
-聚合:Count,Sum,Max.... aggregate
-分组:annotate
-总结:
value在前表示group by,在后,表示取值
filter在前,表示where,在后,表示having
-F函数,Q函数
-F函数,因为等号后面不能传字段,所以用F函数包裹一下
-Q函数:表示与& 或| 非~ 关系
-常用,非常用字段
-常用的记住,非常用的知道
-dateField类型:auto_now和auto_add_now
常用参数:
-级联删除:2.0以后,必须显示指定
-唯一性
-索引
元信息:
-重名名表名
-联合索引
-联合唯一
补充事务:
from django.db import transaction
with transaction.atomic():
# 两条create
pass
补充choice:
-在模型表中定义mychoice=((1,'男'),(2,'女'),(3,'其他'))
-在字段上用:dd = models.IntegerField(choices=mychoice)
-取对应的文字:
-在视图层:(get_字段名_display())
sex=author.get_dd_display()
补充defer和only(数据库优化)
only:只取我指定的字段,返回值是queryset里套对象,只是对象里只有指定的字段
defer:反过来
补充:inclusion_tag
-先注册app
-在app下创建一个templatetags的模块
-在模块下新建一个py文件
-from django.template import Library
-register=Library()------>名字必须叫register
-使用装饰器:@register.inclusion_tag('test.html')
-写个函数my_inclusion,返回字典
-模板里就能取到字典,渲染模板
-使用:
在模板中:{%load py文件名%}
{% my_inclusion 参数%}
补充事务:
from django.db import transaction
with transaction.atomic():
# 两条create
pass
补充choice:
-在模型表中定义mychoice=((1,'男'),(2,'女'),(3,'其他'))
-在字段上用:dd = models.IntegerField(choices=mychoice)
-取对应的文字:
-在视图层:(get字段名display())
sex=author.get_dd_display()
补充defer和only(数据库优化)
only:只取我指定的字段,返回值是queryset里套对象,只是对象里只有指定的字段
defer:反过来
六、组件
一、Django与Ajax
ajax
1 什么是ajax:异步的JavaScript和xml,跟后台交互,都用json
2 ajax干啥用的?前后端做数据交互:
3 之前学的跟后台做交互的方式:
-第一种:在浏览器窗口输入地址(get)
-第二种:用form表单提交数据
4 特点:
-异步(异步和同步的区别:同步是请求发过去,要等着回应;异步:不需要等回应,可以进行其他操作)
-局部刷新:
5 $.ajax({
url:'/index/',
type:'post',
//data:往后台提交的数据
data:{'name':'lqz','age':18},
//成功的时候回调这个函数
success:function (data) {
alert(data)
}
})
6 上传文件
模板层:
$("#btn").click(function () {
//上传文件,必须用FormData,生产一个formdata对象
var formdata=new FormData();
formdata.append('name',$("#name").val());
//取出文件$("#myfile")[0].files拿到的是文件列表,取第0个把具体的文件取出来
formdata.append('myfile',$("#myfile")[0].files[0]);
$.ajax({
url:'/files_ajax/',
type:'post',
//不预处理数据,(name=lqz&age=18)
processData:false,
//指定往后台传数据的编码格式(urlencoded,formdata,json)
//现在用formdata对象处理了,就不需要指定编码格式了,不要给我编码了
contentType:false,
data:formdata,
success:function (data) {
alert(data)
}
})
视图层:(跟form表单上传文件完全一样)
def files_ajax(request):
# 提交文件从,request.FILES中取,提交的数据,从request.POST中取
name=request.POST.get('name')
print(name)
dic_files = request.FILES
myfile = dic_files.get('myfile')
with open(myfile.name, 'wb') as f:
# 循环上传过来的文件
for line in myfile:
# 往空文件中写
f.write(line)
return HttpResponse('ok')
7 基于ajax提交json格式数据
-模板层:
$('#btn').click(function () {
var post_data={'name':$("#name").val(),'pwd':$("#pwd").val()};
console.log(typeof post_data);
// 如何把post_data这个字典,转成json格式字符串
//JSON.stringify相当于python中json.dumpus(post_data)
//pos是个字符串,json格式字符串
var pos=JSON.stringify(post_data);
console.log(typeof pos);
$.ajax({
url:'/json/',
type:'post',
data:pos,
contentType:'application/json',
success:function (data) {
//如果data是json格式字符串,如何转成对象(字典)?
//data=JSON.parse(data)
console.log(typeof data)
console.log(data)
var ret=JSON.parse(data)
console.log(typeof ret)
console.log(ret.status)
//alert(data)
}
})
})
-视图层:
def add_json(request):
if request.method=='GET':
return render(request,'json.html')
print(request.POST)
print(request.GET)
print(request.body)
import json
# res是个字典
res=json.loads(request.body.decode('utf-8'))
print(res)
print(type(res))
dic={'status':'100','msg':'登录成功'}
# return HttpResponse('ok')
# 返回给前台json格式
return HttpResponse(json.dumps(dic))
# return JsonResponse(dic)
-重点:*****
- 请求的编码方式:
contentType:'application/json',
-响应回来解析的方式
dataType:'json',
二、分页器组件
分页器:
-干啥的?数据量大的话,可以分页获取,查看
基本写法:
后端:
-总数据拿出来
-生成分页器Paginator对象(对象里有属性和方法)
-生成当前页的对象,current_page=paginator.page(当前页码)
-取出前台传过来的页码,current_page_num = int(request.GET.get('page'))
-需要有异常捕获
-捕获到,把当前页码设置成第一页前端:
-for循环总页列表
-点某一页,跳到指定页码,<li>{{ foo }}</li>
-上一页,下一页的处理:需要有判断,判断是否有上一页,下一页
-终极版:
#判断总页码数是否大于11,不大于11,走else:把总页码数,赋给page_range(前端循环页码列表,循环的就是page_range)
if paginator.num_pages >11:
# 当前页码数-5大于1的时候,page_range应该是,page_range就是1到11页?
if current_page_num-5<1:
page_range=range(1,12)
elif current_page_num+5>paginator.num_pages:
# 当前页码数+5大于总页码数,总页码-10,到总页码+1之间
page_range=range(paginator.num_pages-10,paginator.num_pages+1)
else:
#其他情况,左5,右6推算,也就是:range(current_page_num - 5, current_page_num + 6)
page_range = range(current_page_num - 5, current_page_num + 6)
else:
#小于11,有多少页,就显示多少页
page_range=paginator.page_range
批量插入输入:
-models.Book.objects.bulk_create(ll)
三、forms组件
1、校验数据
--先定义一个类(继承Form)
--写一些要校验的字段(类型)
--字段(对象)有一些属性(最长多少,最短多少,是否必填,label,错误信息)
--实例化产生forms对象(传字典,也可以不传)
--form对象.is_valid() 为true时才是数据校验通过,只有它执行才会开始校验通过
--form对象.errors当成一个字典(继承字典)--------------对字典的继------所有的错误信息{name:[列表,]}一般取第一个值
--每个字段.errors 列表
2、渲染模板(模板上)
--第一种:{{myform.name}} myform.name拿到的是每个字段对象,只是用它来生产input框(str被重写了)
--第二种:{{for foo in myform}} 推荐使用
--第三种:myform.as_p()
3、渲染错误信息
--form对象的错误信息
--字段的错误信息表
4、局部钩子(能走到他,说明前面的校验已经通过了,但一定能把数据取出来(直接抛异常跳过局部验证))
def clean_字段名(self):
指定字段取出来=self.cleanded_data.get(字段)
做一个判断,一旦失败抛异常(ValidationError)
成功:返回这个字段的值
5、全局钩子(能走到它,前面的全都执行过了,包括局部钩子),在做密码判断时,一定要注意可能密码取出来为空:
def clean(self):
pwd取出来
re_pwd取出来
做判断一旦失败:抛异常(ValidationError)
成功:返回cleanded_data字段
四、cookie组件
1、什么是cookie
存储在客户端浏览器上的键值对
用来记录状态
2、原理
是服务器产生,发给客户端浏览器,浏览器保存下来,下次发请求时,会携带这个键值对到服务器
3、cookie的覆盖
先写了一个键值对,后来再写,会把原来的值覆盖掉
4、cookie的使用
写cookie:在Httpresponse这个对象上(jsonREsponse也可以)写
obj.set_cookie(key,value 参数)
参数用的最多的是超时时间
取cookie:从request对象中取,取出来是个字典request.COOKIES 推荐用get(不会抛异常)
删除cookie:
obj.delete_cookie('name'),从浏览器删除
5、登录认证装饰器,
登录之后才能访问固定的页面
def login_auth(func):
def inner(request, *args, kwargs):
# 拿到之前访问的路径
#这个不行,因为取不到数据部分
#url=request.path
url = request.get_full_path()
is_login = request.COOKIES.get('is_login')
if is_login:
res = func(request, *args, **kwargs)
return res
else:
return redirect('/login/?next=%s' % url)
return inner
cookie的其他属性
加盐cookie
超时时间max_age,传一个秒的时间
超时时间expires,穿一个datatime对象
path='/'可以设置路径,设置路径之后,path='/index/',只有访问index时才会携带cookie过来,根路径说明所以得请求都会携带cookie过来
domain:设置域名下有效domain='map.baidu.com'
secure=False, (默认是false,设置成True浏览器将通过HTTPS来回传cookie)
httponly=True 只能https协议传输,无法被JavaScript获取(不是绝对,底层抓包可以获取到也可以被覆盖)
五、session
1、解决cookie不安全的问题
存在服务器上的键值对{‘随机字符串’:{name:lqz,pwd:123}}
session必须与cookie连用
安全性,客户端浏览器不再存储敏感信息
2、session的使用
设置值
request.session['name']='lqz'
如果设置多个值,他会以字典的形式存储到session表当中的session_data中
3、生产session时
①生成随机字符串:asdadsafa
②去数据库存储
③ 写入cookie(set_cookie('sessionid','dfasfasdfa'))
4、取值
name=request.session['name']
先取出cookie中的随机字符串
去数据库中根据随机字符串查询,拿到data的值
从字典中取出name对应的值
5、执行流程
取到cookie的随机字符串
取session表中根据随机字符串查询,查询出session_data这个字典,然后把字典中的name返回
6、删除值
取出cookie,随机字符串,去数据库删除随机字符串当前值的记录
request.session.delete() 只是删除数据库的内容
request.session.flush() 删除数据库的内容,又删除浏览器的内容
7、session其他属性
request.session.setdefault('k1',123),存在则不设置
取到随机字符串,浏览器带过来的cookie的值
print(request.session.session_key)
内部:request.COOKIES.get('sessionid')
清空失效的session
request.session.clear_expired()
校验sessionid是否存在
request.session.exists("session_key")
8、session的配置 -不但能放到数据库,还能放到文件中,redis(内存数据库)
1. 数据库Session
SESSION_ENGINE = 'django.contrib.sessions.backends.db' # 引擎(默认)
2. 缓存Session
SESSION_ENGINE = 'django.contrib.sessions.backends.cache' # 引擎
SESSION_CACHE_ALIAS = 'default' # 使用的缓存别名(默认内存缓存,也可以是memcache),此处别名依赖缓存的设置
3. 文件Session
SESSION_ENGINE = 'django.contrib.sessions.backends.file' # 引擎
SESSION_FILE_PATH = None # 缓存文件路径,如果为None,则使用tempfile模块获取一个临时地址tempfile.gettempdir()
4. 缓存+数据库
SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db' # 引擎
5. 加密Cookie Session
SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies' # 引擎
其他公用设置项:
SESSION_COOKIE_NAME = "sessionid" # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串(默认)
SESSION_COOKIE_PATH = "/" # Session的cookie保存的路径(默认)
SESSION_COOKIE_DOMAIN = None # Session的cookie保存的域名(默认)
SESSION_COOKIE_SECURE = False # 是否Https传输cookie(默认)
SESSION_COOKIE_HTTPONLY = True # 是否Session的cookie只支持http传输(默认)
SESSION_COOKIE_AGE = 1209600 # Session的cookie失效日期(2周)(默认)
SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 是否关闭浏览器使得Session过期(默认)
SESSION_SAVE_EVERY_REQUEST = False # 是否每次请求都保存Session,默认修改之后才保存(默认)
cbv+装饰器
先导入 from django.utils.decorators import method_decorator
可以在方法上加装饰器
@method_decorator(login_auth)
可以在类上加
@method_decorator(login_auth,name='方法名)
可以加在dishpatch方法上
@method_decorator(login_auth)
一旦加在dishpatch,说明所有方法都加上了装饰器
六、中间件
中间件是什么
请求和响应之间的一道屏障
中间件的作用
控制请求和响应
中间件的方法:执行顺序来的时候按注册时从上往下的顺序,走的时候从下往上的顺序
process_request(self,request):请求来的时候执行
process_response(self,request,response):响应回去时的
return response
自定义中间件
先导入 from django.utils.deprecation import MiddlewareMixin
定义一个类 继承自 MiddlewareMixin
class MyMiddleware1(MiddlewareMixin):
def process_request(self, request):
print('MyMiddleware---->1---->process_request')
# 返回HttpRspons对象,直接返回,走自己的process_response
# 返回None的时候,继续往下走
# return HttpResponse('i am middle--1')
return None
def process_response(self, request, response):
print('MyMiddleware--->1---->process_response')
return response
使用:在setting中注册,是有顺序的,
MIDDLEWARE = [
'app01.mymiddelware.MyMiddleware1',
]
中间件执行顺序
process_request,从上往下
如果retrun HttpResponse的对象,直接返回了
如果retrun None ,继续往下走
process_response,从下往上执行
必须要retrun Httpresponse的对象
中间件的方法:()
process_request
请求来的时候,会响应它
process_response
响应回去的时候,会走它
process_view(了解)
request, callback(视图函数), callback_args(无名分组的参数), callback_kwargs(有名分组的参数)
def process_exception(self, request, exception)(了解)
def process_template_response(self, request, response):(了解)
csrf:跨站请求伪造
比如:转账请求:transfer?to=lqz&count=1000
是什么?攻击者盗用了你的身份,以你的名义发送恶意请求,对服务器来说这个请求是完全合法的
如何防范:通过refer
加一个随机字符串校验(加载请求的路径里,加载请求体中)
在请求头中加字符串校验
django中的应用:
中间件不注释掉
以后再发post请求,携带那个随机字符串
-form表单形式:
<form action="" method="post">
{% csrf_token %}
<input type="text" name="name">
<input type="text" name="pwd">
<input type="submit" value="提交">
</form>
-ajax提交
data: {
'name': $('[name="name"]').val(),
'pwd': $('[name="pwd"]').val(),
//'csrfmiddlewaretoken': $('[name="csrfmiddlewaretoken"]').val()
'csrfmiddlewaretoken': '{{ csrf_token }}'
},
csrf:局部禁用,局部使用
用装饰器:from django.views.decorators.csrf import csrf_exempt,csrf_protect
fbv--->直接加载fbv上就行了
局部禁用,全局得使用
-局部禁用,全局得使用
@csrf_exempt
def csrf_disable(request):
print(request.POST)
return HttpResponse('ok')
-局部使用,全局得禁用
@csrf_protect
def csrf_disable(request):
print(request.POST)
return HttpResponse('ok')
-cbv-->只能加在dispatch方法或者类上面
-局部禁用,全局得使用
-局部使用,全局得禁用
from django.views import View
from django.utils.decorators import method_decorator
@method_decorator(csrf_protect,name='dispatch')
class Csrf_disable(View):
# @method_decorator(csrf_protect)
def dispatch(self, request, *args, **kwargs):
ret=super().dispatch(request, *args, **kwargs)
return ret
def get(self,request):
return HttpResponse('ok')
def post(self,request):
return HttpResponse('post---ok')
作业:
1 登录认证,写在中间件中(只有登录的请求不需要登录以后操作,其他请求,都必须登录以后操作)
2 写一个频率控制的中间件(任意用户,一分钟只能访问3次)应用上csrf
-思路:
-当前访问的ip地址取出来
-存一个临时变量{ip:[时间1,时间2,时间3]}
中间件回顾
django请求生命周期
中间件:对全球请求的修改,和全局响应的修改
process_request:处理请求信息 从上往下
process_response:处理响应信息 从下往上
process_view:拿到视图层的数据,直接跳过视图层
process_exception:拿到出错的信息处理
process_template_respomse:只有render时才有用
自定义中间件
csrf:跨站请求伪造:
django处理这种攻击:使用中间件
往后台传json数据,可以放在头中
xss攻击:跨站脚本攻击:可以提交脚本代码渲染到页面,
局部,全局禁用csrf:
全局禁用:注释中间件
局部使用:
fbv
from django.views.decorators.csrf import csrf_exempt,csrf
@csrf_protect
视图函数
-cbv
from django.untils.decorators import method_decorator
只能加在类上(name=dispatch),或者加载dispatatch方法上
七、auth组件
今日内容:
auth组件:
auth是什么? django自带的用户认证系统,可以快速的实现,登录,注销,修改密码
怎么用:
from django.contrib import auth
def login(request)
if request.method=='GET':
return render(request,'login.html')
elif request.method=='POST':
name=request.POST.get('name')
pwd=request.POST.get('pwd')
user=auth.authenticate(username=name,password=pwd).fist()
if user:
登录,将登陆的用户信息放到session中
auth.login(request,user)
return Httpresponse('登陆成功')
else:
return Httpresponse('登陆失败')
(1)创建超级用户:
python manage.py createsuperuser
Username:
Email address: NONE
Password:
Password(again):
也就是在auth_user这个表中插入了一条数据(密码是加密的,所以我们不能手动加入数据)
(2)验证用户:
from django.contrib import auth
user=auth.authenticate(username=name,password=pwd).fist()
相当于在查询:user=models.User.object.filter(username=name,password=pwd).first()
如果校验通过会返回一个user的对象,通过判断user对象,校验是否登录成功
(3)登录
auth.login(request,user)
其实就是在session中写了一条数据
(4)一旦登陆成功,掉了这个函数login(request,usr)
以后在视图函数,函数中的request对象中,就有了一个user对象,就是当前登录的用户对象
如果没有登录,request.user=AnonymousUser,匿名用户
(5)注销:
auth.logout(request)
内部调用了request.session.flush(),删除登录状态
(6)登录认证装饰器:
from django.contrib.auth.decorators import login_required
@login_required()
redirect_filed_name:修改后面的key值
login_url:如果没有邓丽跳转到页面
可以局部配置///;直接在后面
可以全局配置:在settings中LOGIN_URL='//'
(7)创建用户:
from django.contrib.auth.models import User
创建超级用户和普通用户
不能用create
user=User.object.create(username=name,password=pwd)
创建超级用户
user=User.objects.create_superuser(username=name,password=pwd)
创建普通用户
user=User.objects.create_user(username=name,password=pwd)
(8)校验密码
request.user.check_password(pwd)
先拿到用户(可以是登录用户,可以现查)
(9)修改密码:
user.set_password(pwd)
user.save()
注意:一定要调用save(),否则是不保存的
(10)is_authenticated()
如果通过验证,是true反之false
(11)其他方法(了解):
is_active:禁止登录网站(用户还存在,封号)
is_staff:是否对网站有管理权限(能不能登录admin)
(12)删除用户
orm删除
如果想在认证组件上加手机号等其他字段:如何处理
(1) 定义一个表模型,跟User一对一管理
class UserDetail(models.Model):
phone=models.CharField(max_length=32)
# 一对一跟auth_user表做关联
# 如果是从外部引入的表模型,是不能加引号的
# 如果加引号,只是在当前model找
user=models.OneToOneField(to=User)
(2)定义一个表模型,继承(AbstractUser)
-from django.contrib.auth.models import AbstractUser
class UserInfo(AbstractUser):
# username,password...都有
phone=models.CharField(max_length=32)
sex=models.BooleanField()
在setting中配置:
AUTH_USER_MODEL ='app01.UserInfo'
做数据库迁移,以后就没有auth_user这个表了,以后认证组件用的表就是UserInfo
原来auth中的其他操作:
-authentication -login -logout -set_password ....
一样用,完全一样
不一样的地方: 如果之前用到User这个表模型的地方,都换成UserInfo
博客项目
1、需求分析
首页(显示文章)
文章详情页
点赞点踩
文章评论
子评论
评论展示
登录功能(图片验证码)
注册功能(基于forms验证,ajax)
个人站点:(不同人不同样式,文章过滤)
后台功能:
2、设计程序(框架,数据库)
使用django框架
数据库设计
userinfo-----用户表
Article--------文章表
commit--------评论表
upanddown---------点赞点踩表
category--------文章分类表
tag -----------标签表
blog-------个人站点表-------userinfo 一对一
表关系:
userinfo-------blog-----------一对一
article--------blog ------- 一对多的关系
article----------category--------(一个文章只能用一个分类,一个分类下有多个文章)一对多
article----------tag-----------(一个标签可以对应多篇文章,一篇文章可以有多个标签)多对多
commit-------article-------一对多
upanddown-----------article ------一对多
user------commit------一对多
user-------------upanddown---------一对多
category----------blog-------一对多
tag-------blog---------一对多
3、分发任务
4、测试
5、上线
浙公网安备 33010602011771号