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[0-9]{4})/(?P[0-9]{2})/$', views.publish),

    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[0-9]{4})/(?P[0-9]{2})/$',         views.publishadd,name='ddd'),

  在模板层:

    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\d+.html)',views.book),

    访问: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、上线

posted on 2018-11-26 19:04  一条流浪鱼  阅读(279)  评论(0)    收藏  举报

导航