Django 进阶

本节内容:

    1、Cookie

    2、Session

    3、Django From

    4、Django Model

    5、Django ModelFrom

    6、中间件

    7、CSRF

    8、缓存

    9、信号

 

一、Cookie

  什么是Cookie:保存在客户端浏览器的,一些键值对,设置是在;服务器端设置的Cookie。它是在客户端浏览器上,硬盘的某个位置,这个Cookie,客户端每次发来请求都携带着。

  为什么要有呢?(因为http是无状态的,链接上一下就又断开了,断开以后就没有状态了,如果没有cookie,一个人登录成功页面,其他人不要登录,直接输入网址就可以进去了,还有一个就是,每个人登录看自己的信息,如果没有一个特殊的东西,做用户认证做不了,我不知道是谁登录了。

 

 

获取Cookie

request.COOKIES['key']

 

 

 

 设置Cookie

 

rep=redicect("/index.html")  //登录成功后返回的页面
rep.set_cookie(key,value,...)   //生成字符串下次来记得
return rep

 

  

返回的内容里面要包点Cookie,我们就可以先换成 ,先创建个变量,然后接受一下那个返回值得内容,这个对象具有set_cookie方法,然后设置上之后 然后再return rep,这样就携带的Cookie就过去了。这个就保存咋客户端了       还可以通过参数的形式来规定,建值对的生命周期

    参数:
        key,              键
        value='',         值
        max_age=None,     超时时间

        expires=None,       也是超时时间,可以设置取到现在时间,在加当前时间在加多久 用变量接收,然后变量写在=后面



        path='/',         Cookie生效的路径,默认/ 是在全局生效, 表示根路径,特殊的:跟路径的cookie可以被任何url的页面访问,如果你设置上路径,就表示这个cookie只有在你,你设置的那个URL才能读取的到



        domain=None,      Cookie生效的域名,就是设置cookie时候,这cookie是那个域名下的



        secure=False,     https传输  有的请求是需要证书的,如果你是基于https访问的,加s一般就是加证书访问,你就得设置成true 就OK了

你如果以证书形式访问,设置cookie和获取cookie 等等操作的时候,把他设置成true(加密的)




        httponly=False    是来做安全用的,但是不能做到绝对的安全,只能做相对的安全,只能http协议传输,无法被JavaScript获取(不是绝对,底层抓包可以获取到也可以被覆盖)抓包就网络请求,可以把你的那个值获取到,抓到以后也可以把你的值修改了。所有就公共网络转账 有危险的
参数

 cookie :

    1、服务端可以操作cookie

    2、客户端也可以操作cookie

    3、cookie保存在客户端的浏览器上

cookie特性:我可以设置在他电脑上,他下次来的时候,还会带着这个来,由于他有这种特性,我可以基于cookie做一个用户登录验证

cookie应用:

    登录验证,当登录完了之后,就把cookie写在客户端了,他下次来的时候,还会带着这个来,就不用每次都去数据库里取数据了 ,但是如果里面有敏感信息,不适合直接放在cookie里面直接搞过来,如果非得有cookie做,就把用户名放那,每次来的时候去数据库里取一下代价就是频繁的操作数据库

  有加密的cookie         设置时        rep.set_signed_cookie(key,value,)     获取时       .get_signed_cookie

  但是加密可能被破解

所以cookie做认证时,将不敏感的信息放在cookie中,频繁的取操作数据库 

 

cookie的整个流程:

  首先服务器端,假设最开始运行起来了,我们浏览器跟服务器端,还没有任何交互,接下来我要点个URL,发起一次http请求,当我发起http请求的时候,他会给我发个东西过去,发个请求头,发一个请求的内容过去,服务器端拿到请求头,拿到内容,可以分析请求头,分析内容这是第一次。分析完了,我要给你返回一个cookie,要给他写cookie了,我给他设置一个响应头。因为响应的内容就包含了,响应头和响应内容,把cookie放在响应里面,就响应头,内容 还有cookie,发给客户端,客户端拿到之后,把cookie放在某个位置就行了,响应头放在这个位置,内容凡在那个位置,这次请求响应就完成了【其实cookie是放在响应头里面的给发过过来的】所以服务端给响应过来的时候就两部分,一部分是响应头其中包含了cookie,还有响应内容,发到浏览器上之后,浏览器取解析他的响应头,把他响应头里的cookie找到,写在自己的文件里面,然后响应的内容显示出来就行了,那接下来发第三次请求了,第三次请求,本地已近有cookie了,就下来就应该把cookie拿过来,发给服务端,那你在去发的时候 ,还是发两部分的内容,他会把cookie封装在请求头里面,以及在加上请求内容,发送给服务器端,服务器端会去他的请求头里面解析他的cookie,如果再想设置,还是在响应头里面设置

 

 

还有另外一种用户认证:

  在用户那里,不会给他任何数据,只会给他一个随机字符串,这个字符串没有任何含义,给了你以后,你就带着随机字符串来,把敏感信息放在我的服务器端,内存里面,或我的缓存里面,放在我的文件里面都可以,这样,就保证用户永远看不到敏感信息。他只有一个什么都不是的字符串(随机字符串)这个叫Session。session会基于cookie来做

 

 

 

 

 

 

 

 

 

二、Session

   session  是服务器端的一个键值对

  session  默认内部机制依赖于cookie

 def index(request):
        # 获取、设置、删除Session中数据

        request.session['k1']  获取值通过索引,如果没有k1就报错 通过get设置默认值   也能通过索引直接获取,通过get直接设置
        request.session.get('k1',None)


        request.session['k1'] = 123这是设置,直接设置上了你不管k1存不存在都会设置,
        request.session.setdefault('k1',123) # 存在则不设置


        del request.session['k1']删除某一个
 
        # 所有字典的 键、值、键值对
        request.session.keys()
        request.session.values()
        request.session.items()
        request.session.iterkeys() ite就是迭代器不一次性全拿到,只有for循环迭代的时候一个一个的 拿
        request.session.itervalues()
        request.session.iteritems()
 
 
        # 用户session的随机字符串
        request.session.session_key
 
        # 将所有Session失效日期小于当前日期的数据删除
        request.session.clear_expired()
 
        # 检查 用户session的随机字符串 在数据库中是否
        request.session.exists("session_key")
 
        # 删除当前用户的所有Session数据
        request.session.delete("session_key")
 
        request.session.set_expiry(value)
            * 如果value是个整数,session会在些秒数后失效。
            * 如果value是个datatime或timedelta,session就会在这个时间后失效。
            * 如果value是0,用户关闭浏览器session就会失效。
            * 如果value是None,session会依赖全局session失效策略。
使用方法

 

简单介绍

 

 

代码

 

 

 

用了session,cookie就不用自己操作了。

Django中默认支持Session,其内部提供了5种类型的Session供开发者使用:

  • 数据库(默认)
  • 缓存
  • 文件
  • 缓存+数据库
  • 加密cookie

 

总结:登录页面了,cookie会做什么,session会做什么?

  单讲cookie来说,他和session本质上,cookie这个东西和session没有关系。但是session和cookie有关系,所以说cookie是单独存在的,他就是放在咱们这个客户端,浏览器上的一些键值队。

  对服务器的session来说,他要依赖于cookie来实现,而还有一点咱们知道,cookie发送到服务端的时候就是依附在请求头里面,回来的时候依附在响应头里面,接下来咱们说整个流程是怎样的。

  我们去服务器端给他发消息,服务器端生成一个随机字符串,然后把这个随机字符串,写到我们的额客户端,并且同时,在他的服务器端,再给我搞一个字典,或者是搞一个什么东西,把这个随机字符串当做key,后面当做vilue,这么一个键值对,这么放就行了,每一个人会生成一个键值对,都是以随机字符串作为key的。

 

 

 

 

 

 

 

 

三、Django From

  Django From是用来帮咱们在后台,做用户请求数据验证的,不管用户传过来的是from请求还是ajax请求,我们在后台都得做验证,并且验证后的错误信息,要传到前端让页面看到。他是验证用户请求数据的合法性的一个组件,如果没有他,我们的验证得通过反复的正则表达式来验证。

  以后要想对用户提交过来的数据,进行表单验证,分以下几步:

  1、创建模板

  模板是用来,当用户发来数据之后,我模板里面有几个字段(元素)我就验证几个。

  创建模板有三个关键字: 一个类(自己命名)               一个字段(字段名是你前端input框的name的名字)              一个插件(这是jango内部定义的,)

  字段是用来验证,用户请求数据的,只验证(某个字段)        插件就是:写什么插件页面出什么效果    

创建模板先引入forms

form django import forms

class 自己命名(forms.Form):    #继承

  字段名 = forms.CharFied(里面可以写,是否必填,长短指定等,插件也是在这里面)    #CharFied就是类型,有很多种类型,有邮箱格式的 ,密码格式的等

 你得保证你的字段名和前端提交过来input框的name名字一样,要不就验证不到了 出错了

  模板创建完之后

  2、接收用户请求,然后传给模板(创建个对象)

现在还没有检测

 

 

 

  3、检测

 

 如果想要自己设定错误信息,得在字段后面添加参数

 

 

 总结一下:

    1、创建模板

    2、接收用户请求,然后传给模板(创建对象)

    3、调用is_valid检测是否成功,(这个方法就是他在内部,把你设置的那两个字段,两条验证规则全部执行一遍,就是个for循环,在执行过程中,全部成功了,返回一个true,有一个失败就是false)

       调用clean_data,获取正确的值(返回的是字典)

         调用errors来获取所有的错误信息

 

 

 获取错误信息

errors方法直接写在前端HTML

后端打印出来的

 

前端获取,如果是别的框架,就会报错,因为get请求后面没传值,就去取信息了,jango不报错是,jango取不到就认为是空jango帮你做的,其他的框架不传就报错了

 

就说form提交数据时候,具有刷新页面的特性,再显示时,值和错误信息要想都有,就在get请求里也创建对象,让他自动生成HTML标签,保留上一次提交数据

 

 

HTML

 

 插件:就是生成什么标签,默认是Text input标签,可以改成密码,邮箱 等

视图函数

 

HTML

页面

还有一种是,统一的操作._as

 

 

 

 

 

 创建Form类时,主要涉及到 【字段】 和 【插件】,字段用于对用户请求数据的验证,插件用于自动生成HTML;

  1 Field(父级)
  2     required=True,               是否必填
  3     initial=None,                初始值,默认值
  4     validators=[],               自定义验证规则
  5     error_messages=None,         错误信息 后面跟字典{'required': '不能为空', 'invalid': '格式错误'}
  6 
  7 
  8 
  9 
 10 
 11     widget=None,                 HTML插件
 12     label=None,                  用于生成Label标签或显示内容,通过前端点就可以获取,后台定义前端使用
 13     show_hidden_initial=False,   是否在当前插件后面再加一个隐藏的且具有默认值的插件(可用于检验两次输入是否一直)
 14     localize=False,              是否支持本地化
 15     disabled=False,              是否可以编辑,改成true就不能输入了
 16     label_suffix=None            Label内容后缀
 17  
 18  
 19 
 20 
 21 
 22 
 23 
 24 
 25 CharField(Field)
 26     max_length=None,             最大长度
 27     min_length=None,             最小长度
 28     strip=True                   是否移除用户输入空白
 29  
 30 IntegerField(Field)
 31     max_value=None,              最大值
 32     min_value=None,              最小值
 33 
 34 
 35 EmailField(CharField)      邮箱
 36     ...
 37 
 38 URLField(Field)              URL
 39     ...
 40 
 41 SlugField(CharField)   只允许用户输入 数字,字母,下划线,减号(连字符)
 42     ...
 43 
 44 GenericIPAddressField          验证IP
 45     protocol='both',           both,ipv4,ipv6支持的IP格式
 46     unpack_ipv4=False          解析ipv4地址,如果是::ffff:192.0.2.1时候,可解析为192.0.2.1, PS:protocol必须为both才能启用 
 47 
 48 
 49  
 50 ChoiceField(Field)                 下拉框
 51     ...
 52     choices=(),                选项,如:choices = ((0,'上海'),(1,'北京'),)
 53     required=True,             是否必填
 54     widget=None,               插件,默认select插件
 55     label=None,                Label内容
 56     initial=None,              初始值
 57     help_text='',              帮助提示
 58 
 59 
 60 MultipleChoiceField(ChoiceField)     多选
 61     initial=[1,2]                               多选默认就得是可迭代的
 62     choices=[(1,"刘能"),(2,"赵四"),(3,"谢广坤")]
 63     ...
 64 
 65 RegexField(CharField)
 66     regex,                      自定制正则表达式
 67     max_length=None,            最大长度
 68     min_length=None,            最小长度
 69     error_message=None,         忽略,错误信息使用 error_messages={'invalid': '...'}
 70 
 71  
 72 
 73 
 74 
 75 
 76 
 77 
 78 
 79 
 80 
 81 FloatField(IntegerField)        继承上面的
 82     ...
 83  
 84 DecimalField(IntegerField)        十进制的小数
 85     max_value=None,              最大值
 86     min_value=None,              最小值
 87     max_digits=None,             总长度
 88     decimal_places=None,         小数位长度
 89  
 90 BaseTemporalField(Field)
 91     input_formats=None          时间格式化   
 92  
 93 DateField(BaseTemporalField)    格式:2015-09-01
 94 TimeField(BaseTemporalField)    格式:11:12
 95 DateTimeField(BaseTemporalField)格式:2015-09-01 11:12
 96  
 97 DurationField(Field)            时间间隔:%d %H:%M:%S.%f
 98     ...
 99  
100 
101  
102 
103  
104 FileField(Field)
105     allow_empty_file=False     是否允许空文件
106  
107 ImageField(FileField)      
108     ...
109     注:需要PIL模块,pip3 install Pillow
110     以上两个字典使用时,需要注意两点:
111         - form表单中 enctype="multipart/form-data"
112         - view函数中 obj = MyForm(request.POST, request.FILES)
113  
114 
115  
116  
117 BooleanField(Field)      布尔值
118     ...
119  
120 NullBooleanField(BooleanField)
121     ...
122 
123  
124 
125 
126 
127 
128 
129 
130 ModelChoiceField(ChoiceField)
131     ...                        django.forms.models.ModelChoiceField
132     queryset,                  # 查询数据库中的数据
133     empty_label="---------",   # 默认空显示内容
134     to_field_name=None,        # HTML中value的值对应的字段
135     limit_choices_to=None      # ModelForm中对queryset二次筛选
136      
137 ModelMultipleChoiceField(ModelChoiceField)
138     ...                        django.forms.models.ModelMultipleChoiceField
139  
140  
141      
142 TypedChoiceField(ChoiceField)       类型转换
143     coerce = lambda val: val   对选中的值进行一次转换
144     empty_value= ''            空值的默认值
145  
146 
147  
148 TypedMultipleChoiceField(MultipleChoiceField)
149     coerce = lambda val: val   对选中的每一个值进行一次转换
150     empty_value= ''            空值的默认值
151  
152 ComboField(Field)比如你之前写了很多字段,这个字段要满足以上几个,使用这个,把之前的Field可以组合起来用
153     fields=()                  使用多个验证,如下:即验证最大长度20,又验证邮箱格式
154                                fields.ComboField(fields=[fields.CharField(max_length=20), fields.EmailField(),])
155  
156 MultiValueField(Field)                    可扩展
157     PS: 抽象类,子类中可以实现聚合多个字典去匹配一个值,要配合MultiWidget使用
158  
159 SplitDateTimeField(MultiValueField)
160     input_date_formats=None,   格式列表:['%Y--%m--%d', '%m%d/%Y', '%m/%d/%y']
161     input_time_formats=None    格式列表:['%H:%M:%S', '%H:%M:%S.%f', '%H:%M']
162  
163 FilePathField(ChoiceField)     文件选项,目录下文件显示在页面中
164     path,                      文件夹路径
165     match=None,                正则匹配
166     recursive=False,           递归下面的文件夹
167     allow_files=True,          允许文件
168     allow_folders=False,       允许文件夹
169     required=True,
170     widget=None,
171     label=None,
172     initial=None,
173     help_text=''
174  
175 
176  
177 
178  
179 UUIDField(CharField)           只支持uuid输入的东西,UUID是根据你的网卡,根据当前时间,根据很多机器码,根据很多东西生成的随机字符串
180     ...                                                
Django内置字段 默认
TextInput(Input)
NumberInput(TextInput)
EmailInput(TextInput)
URLInput(TextInput)
PasswordInput(TextInput)
HiddenInput(TextInput)
Textarea(Widget)
DateInput(DateTimeBaseInput)
DateTimeInput(DateTimeBaseInput)
TimeInput(DateTimeBaseInput)
CheckboxInput
Select
NullBooleanSelect
SelectMultiple
RadioSelect
CheckboxSelectMultiple
FileInput
ClearableFileInput
MultipleHiddenInput
SplitDateTimeWidget
SplitHiddenDateTimeWidget
SelectDateWidget
Django内置插件
# 单radio,值为字符串
# user = fields.CharField(
#     initial=2,
#     widget=widgets.RadioSelect(choices=((1,'上海'),(2,'北京'),))
# )
 
# 单radio,值为字符串
# user = fields.ChoiceField(
#     choices=((1, '上海'), (2, '北京'),),
#     initial=2,
#     widget=widgets.RadioSelect
# )
 
# 单select,值为字符串
# user = fields.CharField(
#     initial=2,
#     widget=widgets.Select(choices=((1,'上海'),(2,'北京'),))
# )
 
# 单select,值为字符串
# user = fields.ChoiceField(
#     choices=((1, '上海'), (2, '北京'),),
#     initial=2,
#     widget=widgets.Select
# )
 
# 多选select,值为列表
# user = fields.MultipleChoiceField(
#     choices=((1,'上海'),(2,'北京'),),
#     initial=[1,],
#     widget=widgets.SelectMultiple
# )
 
 
# 单checkbox
# user = fields.CharField(
#     widget=widgets.CheckboxInput()
# )
 
 
# 多选checkbox,值为列表
# user = fields.MultipleChoiceField(
#     initial=[2, ],
#     choices=((1, '上海'), (2, '北京'),),
#     widget=widgets.CheckboxSelectMultiple
# )
常用选择插件

 以后想对某一个字段,在错误级别,做更详细的定制的时候:

  一个字段级别的

 

    在执行,验证完正则以后才会执行这个方法,这是验证自定义每个字段级别的。
    通过正则的验证以后,正确的值就保存在clean_data(clean方法的原码)
    可以赋给一个变量,取到值,做些验证
    如果value==“root”我才让通过,
    让通过的时候你得做一件事,返回一个值,你返回的值是什么,那个clean_data里面的值就是什么(更换了)
    返回的是value,因为只有是root时候才让通过


否则:不满足我的条件时,我就让他报错,原码有捕捉错误的得调用模块。
from django.core.exceotions import ValidationError
    else:
        raise  ValidationError("你想填的内容")
注释

整体级别的有两个方法  clean       _post_Clean

 

 _post_Clean

 

 

    1、用户验证,首先用户发来一大堆的请求,请求里面有各种各样的数据,假设发来的数据都是字典,有很多,那接下来在我的后端,得把那些大字典传给我的from。


    2、所以咱们创建from对象的时候,obj=类名(request.POST)
这个时候只是把整体的数据,传给obj了,还没有任何的操作,也没有做验证。


    3、所以在执行obj=is_valid()的时候,在这,他有好多级别的验证;第一步他会循环From对象中所有的字段,根据字段名(也是字典的键),去用户请求中获取数据,获取到数据后,接下来得听过正则表达式的验证,这些正则表达式是封装在Fied对象里的,得去内部去做验证,调用字段的clean方法进行正则表达式的验证。到这,咱们自定义的方法还没执行,所以默认情况下只执行正则表达式的。
    当正则表达式执行完之后,紧接着会执行另外一个操作,当前字段是有名字的,他在会调用一下当前字段前面有一个clean_name (name代指的就是字段名),他就会执行这个方法,那在这个方法的内部会对这个单独的字段进行操作clean_name,是调用的self所以self.clean_name  此时的self是From的对象obj。
    此时的self.clean_name这就是调用你自定义验证的那一个字段,也就是self.clean_username    ,验证单一字段的结束



    4、还有整体级别的验证方法,可以自定义clean方法。
    clean方法是支持抛出异常,因为在他外面有try except 方法,可以接收里面的异常,一但有异常就会加到error里面,当主动抛出异常时,它是不属于某一个,单一字段的,他的异常会保存在__all__里面,表示整体错误,如果你的clean方法里抛出异常了,内部就消化了,不会报错,只是把错误信息放到里面,整个程序不终止继续执行。



    5、自定义的_post_clean方法里面,自己没有包含任何的代码,我如果继承了他,他会调用我,调用我的时候,我里面不能出错,如果出错,整个程序就崩溃了,所以在我们自定义的_post_clean时候,不允许出现异常,不允许出现异常,但是那个错误还是要捕捉到,所以我们会选择执行一个add_error,把错误放里面就行了
    
注释及流程介绍

  

 

对下拉框进行操作时候 ,做到实时更新(就是数据库加进去数据直接就显示不用刷新页面

 

  方法1,自己设定__init__

 方法 2 不用init方法  但是数据库那边 做个操作

 

数据库加字段名加str方法

还有一个多选框

 

 

 

 

 

 

 

 

 

四、Django Model

    Model 主要是强大的数据库操作(也能和from自定义验证字段),弱小的数据验证(ORM)【增、改】

    对数据库的表、行  进行操作。

  

    类级别

    创建类········>自动生成表

    执行命令:python manage.py makemigrations                 python manage.py migrate         

              python manage.py migrate --fake    用来解决数库,跟类同步(删除表时候)   

 

    字段级别:字符串,数字、时间、二进制、还有文件     关系:(一对一)、(一对多)、(多对多)  参数:用于指定生成库列的信息,用于验证(admin、ModelForm)

       字符串:在jango里面原生字符串,再加一个带正则表达式的字符串

       数字:就是在数据库级别,他的长度是多少,比如说有些数字的长度,就应该是11位有些就应该是4位,范围不同而已,创建数字时候,指定长度是没有用的,因为他本质是上在内存里面,存的时候,他自己会按照自己的长度去存,你给他设置了也是不生效的。

       时间:和字符串级别一样

       二进制:存二进制数据       

    AutoField(Field)
        - int自增列,必须填入参数 primary_key=True

    BigAutoField(AutoField)
        - bigint自增列,必须填入参数 primary_key=True

        注:当model中如果没有自增列,则自动会创建一个列名为id的列
        from django.db import models

        class UserInfo(models.Model):
            # 自动创建一个列名为id的且为自增的整数列
            username = models.CharField(max_length=32)

        class Group(models.Model):
            # 自定义自增列
            nid = models.AutoField(primary_key=True)
            name = models.CharField(max_length=32)

    SmallIntegerField(IntegerField):
        - 小整数 -32768 ~ 32767

    PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
        - 正小整数 0 ~ 32767
    IntegerField(Field)
        - 整数列(有符号的) -2147483648 ~ 2147483647

    PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
        - 正整数 0 ~ 2147483647

    BigIntegerField(IntegerField):
        - 长整型(有符号的) -9223372036854775808 ~ 9223372036854775807

    BooleanField(Field)
        - 布尔值类型

    NullBooleanField(Field):
        - 可以为空的布尔值

    CharField(Field)
        - 字符类型
        - 必须提供max_length参数, max_length表示字符长度

    TextField(Field)
        - 文本类型

    EmailField(CharField):
        - 字符串类型,Django Admin以及ModelForm中提供验证机制

    IPAddressField(Field)
        - 字符串类型,Django Admin以及ModelForm中提供验证 IPV4 机制

    GenericIPAddressField(Field)
        - 字符串类型,Django Admin以及ModelForm中提供验证 Ipv4和Ipv6
        - 参数:
            protocol,用于指定Ipv4或Ipv6, 'both',"ipv4","ipv6"
            unpack_ipv4, 如果指定为True,则输入::ffff:192.0.2.1时候,可解析为192.0.2.1,开启刺功能,需要protocol="both"

    URLField(CharField)
        - 字符串类型,Django Admin以及ModelForm中提供验证 URL

    SlugField(CharField)
        - 字符串类型,Django Admin以及ModelForm中提供验证支持 字母、数字、下划线、连接符(减号)

    CommaSeparatedIntegerField(CharField)
        - 字符串类型,格式必须为逗号分割的数字

    UUIDField(Field)
        - 字符串类型,Django Admin以及ModelForm中提供对UUID格式的验证

    FilePathField(Field)
        - 字符串,Django Admin以及ModelForm中提供读取文件夹下文件的功能
        - 参数:
                path,                      文件夹路径
                match=None,                正则匹配
                recursive=False,           递归下面的文件夹
                allow_files=True,          允许文件
                allow_folders=False,       允许文件夹

    FileField(Field)
        - 字符串,路径保存在数据库,文件上传到指定目录
        - 参数:
            upload_to = ""      上传文件的保存路径
            storage = None      存储组件,默认django.core.files.storage.FileSystemStorage

    ImageField(FileField)
        - 字符串,路径保存在数据库,文件上传到指定目录
        - 参数:
            upload_to = ""      上传文件的保存路径
            storage = None      存储组件,默认django.core.files.storage.FileSystemStorage
            width_field=None,   上传图片的高度保存的数据库字段名(字符串)
            height_field=None   上传图片的宽度保存的数据库字段名(字符串)

    DateTimeField(DateField)
        - 日期+时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]

    DateField(DateTimeCheckMixin, Field)
        - 日期格式      YYYY-MM-DD

    TimeField(DateTimeCheckMixin, Field)
        - 时间格式      HH:MM[:ss[.uuuuuu]]

    DurationField(Field)
        - 长整数,时间间隔,数据库中按照bigint存储,ORM中获取的值为datetime.timedelta类型

    FloatField(Field)
        - 浮点型

    DecimalField(Field)
        - 10进制小数
        - 参数:
            max_digits,小数总长度
            decimal_places,小数位长度

    BinaryField(Field)
        - 二进制类型
字段类型
    null                数据库中字段是否可以为空
    db_column           数据库中字段的列名
    default             数据库中字段的默认值
    primary_key         数据库中字段是否为主键
    db_index            数据库中字段是否可以建立索引
    unique              数据库中字段是否可以建立唯一索引
    unique_for_date     数据库中字段【日期】部分是否可以建立唯一索引
    unique_for_month    数据库中字段【月】部分是否可以建立唯一索引
    unique_for_year     数据库中字段【年】部分是否可以建立唯一索引

    verbose_name        Admin中显示的字段名称
    blank               Admin中是否允许用户输入为空
    editable            Admin中是否可以编辑
    help_text           Admin中该字段的提示信息
    choices             Admin中显示选择框的内容,用不变动的数据放在内存中从而避免跨表操作
                        如:gf = models.IntegerField(choices=[(0, '何穗'),(1, '大表姐'),],default=1)

    error_messages      自定义错误信息(字典类型),从而定制想要显示的错误信息;
                        字典健:null, blank, invalid, invalid_choice, unique, and unique_for_date
                        如:{'null': "不能为空.", 'invalid': '格式错误'}

    validators          自定义错误验证(列表类型),从而定制想要的验证规则
                        from django.core.validators import RegexValidator
                        from django.core.validators import EmailValidator,URLValidator,DecimalValidator,\
                        MaxLengthValidator,MinLengthValidator,MaxValueValidator,MinValueValidator
                        如:
                            test = models.CharField(
                                max_length=32,
                                error_messages={
                                    'c1': '优先错信息1',
                                    'c2': '优先错信息2',
                                    'c3': '优先错信息3',
                                },
                                validators=[
                                    RegexValidator(regex='root_\d+', message='错误了', code='c1'),
                                    RegexValidator(regex='root_112233\d+', message='又错误了', code='c2'),
                                    EmailValidator(message='又错误了', code='c3'), ]
                            )
字段参数
    ForeignKey(ForeignObject) # ForeignObject(RelatedField)
        to,                         # 要进行关联的表名
        to_field=None,              # 要关联的表中的字段名称
        on_delete=None,             # 当删除关联表中的数据时,当前表与其关联的行的行为
                                        - models.CASCADE,当删除关联数据,与之关联也删除
                                        - models.DO_NOTHING,当删除关联数据,引发错误IntegrityError
                                        - models.PROTECT,当删除关联数据,引发错误ProtectedError
                                        - models.SET_NULL,当删除关联数据,与之关联的值设置为null(前提FK字段需要设置为可空)
                                        - models.SET_DEFAULT,当删除关联数据,与之关联的值设置为默认值(前提FK字段需要设置默认值)
                                        - models.SET,删除关联数据,
                                                      a. 与之关联的值设置为指定值,设置:models.SET(值)
                                                      b. 与之关联的值设置为可执行对象的返回值,设置:models.SET(可执行对象)

                                                        def func():
                                                            return 10

                                                        class MyModel(models.Model):
                                                            user = models.ForeignKey(
                                                                to="User",
                                                                to_field="id"
                                                                on_delete=models.SET(func),)
        related_name=None,          # 反向操作时,使用的字段名,用于代替 【表名_set】 如: obj.表名_set.all()
        related_query_name=None,    # 反向操作时,使用的连接前缀,用于替换【表名】     如: models.UserGroup.objects.filter(表名__字段名=1).values('表名__字段名')
        limit_choices_to=None,      # 在Admin或ModelForm中显示关联数据时,提供的条件:
                                    # 如:
                                            - limit_choices_to={'nid__gt': 5}
                                            - limit_choices_to=lambda : {'nid__gt': 5}

                                            from django.db.models import Q
                                            - limit_choices_to=Q(nid__gt=10)
                                            - limit_choices_to=Q(nid=8) | Q(nid__gt=10)
                                            - limit_choices_to=lambda : Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root')
        db_constraint=True          # 是否在数据库中创建  外键  约束  不约束了,但是还可以连表操作
        parent_link=False           # 在Admin中是否显示关联数据


    OneToOneField(ForeignKey)
        to,                         # 要进行关联的表名
        to_field=None               # 要关联的表中的字段名称
        on_delete=None,             # 当删除关联表中的数据时,当前表与其关联的行的行为

                                    ###### 对于一对一 ######
                                    # 1. 一对一其实就是 一对多 + 唯一索引
                                    # 2.当两个类之间有继承关系时,默认会创建一个一对一字段
                                    # 如下会在A表中额外增加一个c_ptr_id列且唯一:
                                            class C(models.Model):
                                                nid = models.AutoField(primary_key=True)
                                                part = models.CharField(max_length=12)

                                            class A(C):
                                                id = models.AutoField(primary_key=True)
                                                code = models.CharField(max_length=1)

    ManyToManyField(RelatedField)
        to,                         # 要进行关联的表名
        related_name=None,          # 反向操作时,使用的字段名,用于代替 【表名_set】 如: obj.表名_set.all()
        related_query_name=None,    # 反向操作时,使用的连接前缀,用于替换【表名】     如: models.UserGroup.objects.filter(表名__字段名=1).values('表名__字段名')
        limit_choices_to=None,      # 在Admin或ModelForm中显示关联数据时,提供的条件:
                                    # 如:
                                            - limit_choices_to={'nid__gt': 5}nid大于5 的取到
                                            - limit_choices_to=lambda : {'nid__gt': 5}

                                            from django.db.models import Q
                                            - limit_choices_to=Q(nid__gt=10)
                                            - limit_choices_to=Q(nid=8) | Q(nid__gt=10)
                                            - limit_choices_to=lambda : Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root')
        symmetrical=None,           # 仅用于多对多自关联时,symmetrical用于指定内部是否创建反向操作的字段
                                    # 做如下操作时,不同的symmetrical会有不同的可选字段
                                        models.BB.objects.filter(...)

                                        # 可选字段有:code, id, m1
                                            class BB(models.Model):

                                            code = models.CharField(max_length=12)
                                            m1 = models.ManyToManyField('self',symmetrical=True)

                                        # 可选字段有: bb, code, id, m1
                                            class BB(models.Model):

                                            code = models.CharField(max_length=12)
                                            m1 = models.ManyToManyField('self',symmetrical=False)

        through=None,               # 自定义第三张表时,使用字段用于指定关系表
        through_fields=None,        # 自定义第三张表时,使用字段用于指定关系表中那些字段做多对多关系表
                                        from django.db import models

                                        class Person(models.Model):
                                            name = models.CharField(max_length=50)

                                        class Group(models.Model):
                                            name = models.CharField(max_length=128)
                                            members = models.ManyToManyField(
                                                Person,
                                                through='Membership',
                                                through_fields=('group', 'person'),
                                            )

                                        class Membership(models.Model):
                                            group = models.ForeignKey(Group, on_delete=models.CASCADE)
                                            person = models.ForeignKey(Person, on_delete=models.CASCADE)
                                            inviter = models.ForeignKey(
                                                Person,
                                                on_delete=models.CASCADE,
                                                related_name="membership_invites",
                                            )
                                            invite_reason = models.CharField(max_length=64)
        db_constraint=True,         # 是否在数据库中创建  外键 约束  不约束了,但是还可以连表操作
        db_table=None,              # 默认创建第三张表时,数据库中表的名称(自动生成第三张表时候)
多表关系以及参数
#自己创建多对多
class Book2Author(models.Model)

    book= models.Foreignkey("Book")

    author=models.Foreignkey("Author")
    
    #建立联合唯一
    class Meta:
        unique_together = ["book","author"]

    #建立联合索引
    class Meta:
        index_together = ["book","author"]


#字段索引
username = model.CharField(max_lenght=32,db_index=True)  #普通索引
unique=True     #唯一索引
索引

   

  

    增、删、改、查、(ORM操作)

 

        #
        #
models.表名.objects.create(**{"name":"alex"})
        #create(**字段对象) 列表一个*

        #
        #
        # models.Tb1.objects.get(id=123)         # 获取单条数据,不存在则报错(不建议)
        # models.Tb1.objects.all()               # 获取全部
        # models.Tb1.objects.filter(name='seven') # 获取指定条件的数据
        # models.Tb1.objects.exclude(name='seven') # 获取指定条件的数据

        #
        #
        # models.Tb1.objects.filter(name='seven').delete() # 删除指定条件的数据

        #
        # 
表名.objects.filter(name='wangkuan').update(name='wk')

#update 不能用get   filter,渠道的是一个集合,就把所有等于wangkuan的替换成wk

#get 只会取到一个对象,没有就报错,他不能调用update       
基本操作

增删改查 在上篇博客有详细介绍

        # 获取个数
        #
        # models.Tb1.objects.filter(name='seven').count()

        # 大于,小于
        #
        # models.Tb1.objects.filter(id__gt=1)              # 获取id大于1的值
        # models.Tb1.objects.filter(id__gte=1)              # 获取id大于等于1的值
        # models.Tb1.objects.filter(id__lt=10)             # 获取id小于10的值
        # models.Tb1.objects.filter(id__lte=10)             # 获取id小于10的值
        # models.Tb1.objects.filter(id__lt=10, id__gt=1)   # 获取id大于1 且 小于10的值

        # in
        #
        # models.Tb1.objects.filter(id__in=[11, 22, 33])   # 获取id等于11、22、33的数据
        # models.Tb1.objects.exclude(id__in=[11, 22, 33])  # not in

        # isnull                  #获取这个条件pub_date他为空的东西
        # Entry.objects.filter(pub_date__isnull=True)

        # contains                  模糊比配
        #
        # models.Tb1.objects.filter(name__contains="ven")
        # models.Tb1.objects.filter(name__icontains="ven") # icontains大小写不敏感
        # models.Tb1.objects.exclude(name__icontains="ven")

        # range                       范围查找
        #
        # models.Tb1.objects.filter(id__range=[1, 2])   # 范围bettwen and

        # 其他类似
        #
        # startswith,istartswith, endswith, iendswith,

        # order by             排序
        #
        # models.Tb1.objects.filter(name='seven').order_by('id')    # asc
        # models.Tb1.objects.filter(name='seven').order_by('-id')   # desc

        # group by                .annotate生成having时前面写上filter表示就是where条件,如果在.annotate,后面写filter就表示是having了
        #
        # from django.db.models import Count, Min, Max, Sum
        # models.Tb1.objects.filter(c1=1).values('id').annotate(c=Count('num'))
        # SELECT "app01_tb1"."id", COUNT("app01_tb1"."num") AS "c" FROM "app01_tb1" WHERE "app01_tb1"."c1" = 1 GROUP BY "app01_tb1"."id"

        # limit 、offset             索引
        #
        # models.Tb1.objects.all()[10:20]

        # regex正则匹配,iregex 不区分大小写
        #
        # Entry.objects.get(title__regex=r'^(An?|The) +')
        # Entry.objects.get(title__iregex=r'^(an?|the) +')
==============对时间进行处理的
        # date
        #
        # Entry.objects.filter(pub_date__date=datetime.date(2005, 1, 1))
        # Entry.objects.filter(pub_date__date__gt=datetime.date(2005, 1, 1))

        # year
        #
        # Entry.objects.filter(pub_date__year=2005)
        # Entry.objects.filter(pub_date__year__gte=2005)

        # month
        #
        # Entry.objects.filter(pub_date__month=12)
        # Entry.objects.filter(pub_date__month__gte=6)

        # day
        #
        # Entry.objects.filter(pub_date__day=3)
        # Entry.objects.filter(pub_date__day__gte=3)

        # week_day
        #
        # Entry.objects.filter(pub_date__week_day=2)
        # Entry.objects.filter(pub_date__week_day__gte=2)

        # hour
        #
        # Event.objects.filter(timestamp__hour=23)
        # Event.objects.filter(time__hour=5)
        # Event.objects.filter(timestamp__hour__gte=12)

        # minute
        #
        # Event.objects.filter(timestamp__minute=29)
        # Event.objects.filter(time__minute=46)
        # Event.objects.filter(timestamp__minute__gte=29)

        # second
        #
        # Event.objects.filter(timestamp__second=31)
        # Event.objects.filter(time__second=2)
        # Event.objects.filter(timestamp__second__gte=31)
进阶操作
        # extra               子查询还是有局限性的 select  where不能写一起
        #
        # extra(self, select=None, where=None, params=None, tables=None, order_by=None, select_params=None)
select=None   select_params=None  这两个是对应的
 where=None, params=None,  这两个是对应的

        #    Entry.objects.extra(select={'new_id': "select col from sometable where othercol > %s"}, select_params=(1,))
 new_id 这一列支持 "select col from sometable where othercol 这个查询结果


        #    Entry.objects.extra(where=['headline=%s'], params=['Lennon'])
        #    Entry.objects.extra(where=["foo='a' OR bar = 'a'", "baz = 'a'"])
where条件,通过Q也是可以的 逗号就是and条件

        #    Entry.objects.extra(select={'new_id': "select id from tb where id > %s"}, select_params=(1,), order_by=['-nid'])

        # F
        #
        # from django.db.models import F
        # models.Tb1.objects.update(num=F('num')+1)


        # Q
        #
        # 方式一:
        # Q(nid__gt=10)
        # Q(nid=8) | Q(nid__gt=10)
        # Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root')

        # 方式二:
        # con = Q()
        # q1 = Q()
        # q1.connector = 'OR'
        # q1.children.append(('id', 1))
        # q1.children.append(('id', 10))
        # q1.children.append(('id', 9))
        # q2 = Q()
        # q2.connector = 'OR'
        # q2.children.append(('c1', 1))
        # q2.children.append(('c1', 10))
        # q2.children.append(('c1', 9))
        # con.add(q1, 'AND')
        # con.add(q2, 'AND')
        #
        # models.Tb1.objects.filter(con)


        # 执行原生SQL
        #写原生SQL时候不用去链接数据库了,jango配置文件已近写好了
        # from django.db import connection, connections
        #connection这就是数据库链接
        # cursor = connection.cursor()    创建游标  链接
  # cursor = connections['default'].cursor()
        # cursor.execute("""SELECT * from auth_user where id = %s""", [1])
        # row = cursor.fetchone()    
高级操作
def all(self)
    # 获取所有的数据对象

def filter(self, *args, **kwargs)
    # 条件查询
    # 条件可以是:参数,字典,Q

def exclude(self, *args, **kwargs)
    # 条件查询
    # 条件可以是:参数,字典,Q

def select_related(self, *fields)     主动做连表操作
     性能相关:表之间进行join连表操作,一次性获取关联的数据。
     model.tb.objects.all().select_related()
     model.tb.objects.all().select_related('外键字段')
     model.tb.objects.all().select_related('外键字段__外键字段')

def prefetch_related(self, *lookups)
    性能相关:多表连表操作时速度会慢,使用其执行多次SQL查询在Python代码中实现连表操作。
            # 获取所有用户表
            # 获取用户类型表where id in (用户表中的查到的所有用户ID)
            models.UserInfo.objects.prefetch_related('外键字段')



            from django.db.models import Count, Case, When, IntegerField
            Article.objects.annotate(
                numviews=Count(Case(
                    When(readership__what_time__lt=treshold, then=1),
                    output_field=CharField(),
                ))
            )

            students = Student.objects.all().annotate(num_excused_absences=models.Sum(
                models.Case(
                    models.When(absence__type='Excused', then=1),
                default=0,
                output_field=models.IntegerField()
            )))

def annotate(self, *args, **kwargs)
    # 用于实现聚合group by查询

    from django.db.models import Count, Avg, Max, Min, Sum

    v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id'))
    # SELECT u_id, COUNT(ui) AS `uid` FROM UserInfo GROUP BY u_id

    v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id')).filter(uid__gt=1)
    # SELECT u_id, COUNT(ui_id) AS `uid` FROM UserInfo GROUP BY u_id having count(u_id) > 1

    v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id',distinct=True)).filter(uid__gt=1)
    # SELECT u_id, COUNT( DISTINCT ui_id) AS `uid` FROM UserInfo GROUP BY u_id having count(u_id) > 1

def distinct(self, *field_names)
    # 用于distinct去重
    models.UserInfo.objects.values('nid').distinct()
    # select distinct nid from userinfo

    注:只有在PostgreSQL中才能使用distinct进行去重

def order_by(self, *field_names)
    # 用于排序
    models.UserInfo.objects.all().order_by('-id','age')

def extra(self, select=None, where=None, params=None, tables=None, order_by=None, select_params=None)
    # 构造额外的查询条件或者映射,如:子查询

    Entry.objects.extra(select={'new_id': "select col from sometable where othercol > %s"}, select_params=(1,))
    Entry.objects.extra(where=['headline=%s'], params=['Lennon'])
    Entry.objects.extra(where=["foo='a' OR bar = 'a'", "baz = 'a'"])
    Entry.objects.extra(select={'new_id': "select id from tb where id > %s"}, select_params=(1,), order_by=['-nid'])

 def reverse(self):
    # 倒序
    models.UserInfo.objects.all().order_by('-nid').reverse()
    # 注:如果存在order_by,reverse则是倒序,如果多个排序则一一倒序


 def defer(self, *fields):
    models.UserInfo.objects.defer('username','id')
    或
    models.UserInfo.objects.filter(...).defer('username','id')
    #映射中排除某列数据

 def only(self, *fields):
    #仅取某个表中的数据
     models.UserInfo.objects.only('username','id')
     或
     models.UserInfo.objects.filter(...).only('username','id')

 def using(self, alias):
     指定使用的数据库,参数为别名(setting中的设置)

def all(self)
    # 获取所有的数据对象

def filter(self, *args, **kwargs)
    # 条件查询
    # 条件可以是:参数,字典,Q

def exclude(self, *args, **kwargs)
    # 条件查询
    # 条件可以是:参数,字典,Q

def select_related(self, *fields)
     性能相关:表之间进行join连表操作,一次性获取关联的数据。
     model.tb.objects.all().select_related()
     model.tb.objects.all().select_related('外键字段')
     model.tb.objects.all().select_related('外键字段__外键字段')

def prefetch_related(self, *lookups)
    性能相关:多表连表操作时速度会慢,使用其执行多次SQL查询在Python代码中实现连表操作。
            # 获取所有用户表
            # 获取用户类型表where id in (用户表中的查到的所有用户ID)
            models.UserInfo.objects.prefetch_related('外键字段')



            from django.db.models import Count, Case, When, IntegerField
            Article.objects.annotate(
                numviews=Count(Case(
                    When(readership__what_time__lt=treshold, then=1),
                    output_field=CharField(),
                ))
            )

            students = Student.objects.all().annotate(num_excused_absences=models.Sum(
                models.Case(
                    models.When(absence__type='Excused', then=1),
                default=0,
                output_field=models.IntegerField()
            )))

def annotate(self, *args, **kwargs)
    # 用于实现聚合group by查询

    from django.db.models import Count, Avg, Max, Min, Sum

    v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id'))
    # SELECT u_id, COUNT(ui) AS `uid` FROM UserInfo GROUP BY u_id

    v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id')).filter(uid__gt=1)
    # SELECT u_id, COUNT(ui_id) AS `uid` FROM UserInfo GROUP BY u_id having count(u_id) > 1

    v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id',distinct=True)).filter(uid__gt=1)
    # SELECT u_id, COUNT( DISTINCT ui_id) AS `uid` FROM UserInfo GROUP BY u_id having count(u_id) > 1

def distinct(self, *field_names)
    # 用于distinct去重
    models.UserInfo.objects.values('nid').distinct()
    # select distinct nid from userinfo

    注:只有在PostgreSQL中才能使用distinct进行去重

def order_by(self, *field_names)
    # 用于排序
    models.UserInfo.objects.all().order_by('-id','age')

def extra(self, select=None, where=None, params=None, tables=None, order_by=None, select_params=None)
    # 构造额外的查询条件或者映射,如:子查询

    Entry.objects.extra(select={'new_id': "select col from sometable where othercol > %s"}, select_params=(1,))
    Entry.objects.extra(where=['headline=%s'], params=['Lennon'])
    Entry.objects.extra(where=["foo='a' OR bar = 'a'", "baz = 'a'"])
    Entry.objects.extra(select={'new_id': "select id from tb where id > %s"}, select_params=(1,), order_by=['-nid'])

 def reverse(self):
    # 倒序
    models.UserInfo.objects.all().order_by('-nid').reverse()
    # 注:如果存在order_by,reverse则是倒序,如果多个排序则一一倒序


 def defer(self, *fields):
    models.UserInfo.objects.defer('username','id')
    或
    models.UserInfo.objects.filter(...).defer('username','id')
    #映射中排除某列数据

 def only(self, *fields):
    #仅取某个表中的数据
     models.UserInfo.objects.only('username','id')
     或
     models.UserInfo.objects.filter(...).only('username','id')

 def using(self, alias):
     指定使用的数据库,参数为别名(setting中的设置)def all(self)
    # 获取所有的数据对象

def filter(self, *args, **kwargs)
    # 条件查询
    # 条件可以是:参数,字典,Q

def exclude(self, *args, **kwargs)
    # 条件查询
    # 条件可以是:参数,字典,Q

def select_related(self, *fields)
     性能相关:表之间进行join连表操作,一次性获取关联的数据。
     model.tb.objects.all().select_related()
     model.tb.objects.all().select_related('外键字段')
     model.tb.objects.all().select_related('外键字段__外键字段')

def prefetch_related(self, *lookups)
    性能相关:多表连表操作时速度会慢,使用其执行多次SQL查询在Python代码中实现连表操作。
            # 获取所有用户表
            # 获取用户类型表where id in (用户表中的查到的所有用户ID)
            models.UserInfo.objects.prefetch_related('外键字段')



            from django.db.models import Count, Case, When, IntegerField
            Article.objects.annotate(
                numviews=Count(Case(
                    When(readership__what_time__lt=treshold, then=1),
                    output_field=CharField(),
                ))
            )

            students = Student.objects.all().annotate(num_excused_absences=models.Sum(
                models.Case(
                    models.When(absence__type='Excused', then=1),
                default=0,
                output_field=models.IntegerField()
            )))

def annotate(self, *args, **kwargs)
    # 用于实现聚合group by查询

    from django.db.models import Count, Avg, Max, Min, Sum

    v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id'))
    # SELECT u_id, COUNT(ui) AS `uid` FROM UserInfo GROUP BY u_id

    v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id')).filter(uid__gt=1)
    # SELECT u_id, COUNT(ui_id) AS `uid` FROM UserInfo GROUP BY u_id having count(u_id) > 1

    v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id',distinct=True)).filter(uid__gt=1)
    # SELECT u_id, COUNT( DISTINCT ui_id) AS `uid` FROM UserInfo GROUP BY u_id having count(u_id) > 1

def distinct(self, *field_names)
    # 用于distinct去重
    models.UserInfo.objects.values('nid').distinct()
    # select distinct nid from userinfo

    注:只有在PostgreSQL中才能使用distinct进行去重

def order_by(self, *field_names)
    # 用于排序
    models.UserInfo.objects.all().order_by('-id','age')

def extra(self, select=None, where=None, params=None, tables=None, order_by=None, select_params=None)
    # 构造额外的查询条件或者映射,如:子查询

    Entry.objects.extra(select={'new_id': "select col from sometable where othercol > %s"}, select_params=(1,))
    Entry.objects.extra(where=['headline=%s'], params=['Lennon'])
    Entry.objects.extra(where=["foo='a' OR bar = 'a'", "baz = 'a'"])
    Entry.objects.extra(select={'new_id': "select id from tb where id > %s"}, select_params=(1,), order_by=['-nid'])

 def reverse(self):
    # 倒序
    models.UserInfo.objects.all().order_by('-nid').reverse()
    # 注:如果存在order_by,reverse则是倒序,如果多个排序则一一倒序


 def defer(self, *fields):
    models.UserInfo.objects.defer('username','id')
    或
    models.UserInfo.objects.filter(...).defer('username','id')
    #映射中排除某列数据

 def only(self, *fields):
    #仅取某个表中的数据
     models.UserInfo.objects.only('username','id')
     或
     models.UserInfo.objects.filter(...).only('username','id')

 def using(self, alias):
     指定使用的数据库,参数为别名(setting中的设置)
def first(self):
   # 获取第一个

def last(self):
   # 获取最后一个

def in_bulk(self, id_list=None):
   # 根据主键ID进行查找
   id_list = [11,21,31]
   models.DDD.objects.in_bulk(id_list)

def delete(self):
   # 删除

def update(self, **kwargs):
    # 更新

def exists(self):
   # 是否有结果
def count(self):
   # 获取个数

def get(self, *args, **kwargs):
   # 获取单个对象

def create(self, **kwargs):
   # 创建对象
其他

 

    

 

 

 

 

 

五、Django ModelFrom

   ModelFrom适中的数据库操作,强大的数据验证         用于数据处理和用户请求的验证。

   适用场景;你写的程序是小程序,小到什么程度呢?你的后台和前台没有做分离,让ORM跟你的,操作views都放在一起的时候,这个东西就适合了。适合到什么程度呢!他可以利用数据库的字段,以及利用你自己的From,  又可以利用你的数据库,操作这些东西,全部都可以在页面上显示出来,并且给你做验证,并且保存数据,以及修改数据。

  ModelFrom   创建

接下来的操作和from是一样的,如果表中有关联表,一对多,多对多,前端直接 obj.as_p  下拉框也就都出来了 但是可以将用户提交的数据添加到数据库,但是不能做删除

.save()内部其实还做了几件事情,你也可以把它拆开     save里面有个参数commit 默认是true

 

 

 

还可以对提交过来的数据进行修改

    1、nid去接受户输入的数据,

    2、如果是get请求,根据nid获取对应的数据库对象。(model_obj)
拿到对象以后我们要把 model_obj后台获取的数据传给前端,显示在页面上
 
    3、创建对象obj ,=后面就是创建modelfrom的那个类名里面有一个方法instance,通过他来传 

    4、返回一个页面模板的obj就是,前端要生成input框,nid是传递给HTML,from表单提交的路径的,得获取当前的nid,要不URL那有正则 过不去

    5、修改原先数据在提交就是post请求了,其他的没变,传数据时候后面多了 request.POST。这是要回去用户输入过来的数据。后面可以不加instance=model_obj,但是那就会认为是,数据是增加的而不受修改的

    6、同样可以做验证然后保存
注释

 ModelFrom参数

ModelForm
    a.  class Meta:
            model,                           # 对应Model的
            fields=None,                     # 字段,里面可以是列表["name"],就显示那个model的name字段
            exclude=None,                    # 排除哪些字段也是列表的形式
            labels=None,                     # 提示信息
            help_texts=None,                 # 帮助提示信息
            widgets=None,                    # 自定义插件
            error_messages=None,             # 自定义错误信息(整体错误信息from django.core.exceptions import NON_FIELD_ERRORS)
            field_classes=None               # 自定义字段类 (也可以自定义字段)
            localized_fields=('birth_date',) # 本地化,如:根据不同时区显示数据
            如:
                数据库中
                    2016-12-27 04:10:57
                setting中的配置
                    TIME_ZONE = 'Asia/Shanghai'
                    USE_TZ = True
                则显示:
                    2016-12-27 12:10:57
    b. 验证执行过程
        is_valid -> full_clean -> 钩子 -> 整体错误
 
    c. 字典字段验证
        def clean_字段名(self):
            # 可以抛出异常
            # from django.core.exceptions import ValidationError
            return "新值"
    d. 用于验证
        model_form_obj = XXOOModelForm()
        model_form_obj.is_valid()
        model_form_obj.errors.as_json()
        model_form_obj.clean()
        model_form_obj.cleaned_data
    e. 用于创建
        model_form_obj = XXOOModelForm(request.POST)
        #### 页面显示,并提交 #####
        # 默认保存多对多
            obj = form.save(commit=True)
        # 不做任何操作,内部定义 save_m2m(用于保存多对多)
            obj = form.save(commit=False)
            obj.save()      # 保存单表信息
            obj.save_m2m()  # 保存关联多对多信息
 
    f. 用于更新和初始化
        obj = model.tb.objects.get(id=1)
        model_form_obj = XXOOModelForm(request.POST,instance=obj)
        ...
 
        PS: 单纯初始化
            model_form_obj = XXOOModelForm(initial={...})
参数

 两个中间还可以定义一个字段

    这个From字段用于页面显示,以及用户验证,from字段跟数据库储存字段没关系,如果和数据库字段重复,页面上就根据from字段显示,还是from优先。验证也有from验证,数据库直接存就好了,以及验证过了。
    
    如果和数据库不重名,页面上会对增加一个字段,就是让在页面上写了,和保存数据库没关系。

    多写这个有什么用呢?就像有的登录页面会显示,一个月内登录。这条数据不是存储在数据库的,在session里做判断就行了,保存cookie的时候加个时间一个月就行了,所以页面上可以多出字段,但是他和数据库没关系,只是在咱们业务代码级别,我可以拿到这个值,根据这个值在做一些其他的额外的操作。

    所以就是可以定制,页面上是可以显示额外的一些数据或者是把原来的那些数据,重新给他覆盖
注释

 

 

 

 

 

 

六、中间件

  先说下生命周期:请求来,我发起请求到你给我结果。

  Django的生命周期:请求来先经过中间件,然后到URL······>视图函数······>数据库(模板)拿数据,再经过渲染得到一个字符串·······>再路过中间件返回给用户

    中间件(管道)就是一个类,类里面有方法

    在django项目的settings模块中,有一个 MIDDLEWARE 变量,其中每一个元素就是一个中间件,如下图。

原理就像这样

 

自己也可以自定义这些中间件 ,

 

 固定的方法 不能改

打印的结果

 

建议自己定义使用的

 

 

中间件中可以定义五个方法,分别是:

  • process_request(self,request)                 请求
  • process_view(self, request, callback, callback_args, callback_kwargs)           请求都走完 不走视图函数,再返回到有view方法的中间件 先把view走完
  • process_exception(self, request, exception)       ( 异常处理)  把上面的view走完,视图函数走完,会走这个异常,走完异常然后返回到最后在一个个的走response,异常处理只会对返回的视图函数有异常会处理
  • process_response(self, request, response)         返回 
  • process_template_response(self,request,response)

 

 

 

 

 

 

 

 

七、CSRF

  跨站伪造请求:他的存在,只能做一部分的,安全性的验证,不能把它作为所有安全的一个准则

    首先你发送get请求,是不会遇到这个阻止,发post时候才有阻止,就是说咱们发post请求的时候,他会要求我额外的在提供一点东西,而这个东西是怎么来的呢?是你第一步先发一个get请求,拿来的,所以 这个csrf,如果你想把它携带上,那你必须发两次http请求。
    第一次来先要你给我一登录页面,其实咱们在页面上看到的不只是登录页面,其实在你的HTML表单里有一大堆东西接下来csrf的原理是:

    我第一次来你这访问发一个get请求,然后你给我发一段东西(证书似的),不仅把页面给我,还给我盖个章,(再给我兜里放个东西【在cookie里】)我要向往你这提交,我可以带着这个章去,你已近给过我验证了,直接去就好了。    
    第二次,你发的就是post请求了,我们对post才做这种验证,所以第二次来的时候带着这个去了,去了之后,我会先验证一下你这个东西,如果你那个不过,后面不让你做任何操作,这属于from表单提交

    做到一部分的防护就是:你直接给我发post请求,不能直接,接受请求。如果说你先发一个get请求,把这个字符串获取到,再发一个post请求这个就是可以的

    对于ajax提交:cookie中提取的 随机字符串名字就叫csrftoken对应的值设置请求头XXOO    cookie中取到的值   设置请求头 之后,给他发请求的时候,带着这个请求头,后台直接就让他通过了

请求头叫什么得自己测
原理

from提交 后端render页面渲染   调用 前端{% csrf_token %}

ajax当前页面的所有ajax做一个同意的配置

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    {% csrf_token %}
  
    <input type="button" onclick="Do();"  value="Do it"/>
  
    <script src="/static/plugin/jquery/jquery-1.8.0.js"></script>
    <script src="/static/plugin/jquery/jquery.cookie.js"></script>
    <script type="text/javascript">
;
  

ajaxSetup当前页面的所有ajax做一个同意的配置
beforeSend发送前前执行的操作

        $.ajaxSetup({
            beforeSend: function(xhr, settings) {
                if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
                    xhr.setRequestHeader("X-CSRFToken",$.cookie('csrftoken'));
                }
            }
        });
        function Do(){
  
            $.ajax({
                url:"/app01/test/",
                data:{id:1},
                type:'POST',
                success:function(data){
                    console.log(data);
                }
            });
  
        }
    </script>
</body>
</html>
View Code

还可以

 

 

 

局部:

  • @csrf_protect,为当前函数强制设置防跨站请求伪造功能,即便settings中没有设置全局中间件。(其他的都不用CSRF,就给个函数用)
  • @csrf_exempt,取消当前函数防跨站请求伪造功能,即便settings中设置了全局中间件。(其他的都用CSRF,就给个函数不用用)

注:

  引入:from django.views.decorators.csrf import csrf_exempt,csrf_protect

 

 

 

 

 

八、缓存

由于Django是动态网站,所有每次请求均会去数据进行相应的操作,当程序访问量大时,耗时必然会更加明显,最简单解决方式是使用:缓存,缓存将一个某个views的返回值保存至内存或者memcache(别的机器的内存)中,5分钟内再有人来访问时,则不再去执行view中的操作,而是直接从内存或者Redis中之前缓存的内容拿到,并返回。

Django中提供了6种缓存方式:

  • 开发调试
  • 内存
  • 文件
  • 数据库
  • Memcache缓存(python-memcached模块)
  • Memcache缓存(pylibmc模块)

最后两种是一种

1、配置(直接复制在setting文件下面)

a、开发调试

复制代码
    # 此为开始调试用,实际内部不做任何操作
    # 配置:
        CACHES = {
            'default': {
                'BACKEND': 'django.core.cache.backends.dummy.DummyCache',     #BACKEND指的就是 引擎 到底用哪种 
=======================下面这些  对下面对的那些配置都适用===================


                'TIMEOUT': 300,                                               # 缓存超时时间(默认300,None表示永不过期,0表示立即过期)
                'OPTIONS':{
                    'MAX_ENTRIES': 300,                                       # 最大缓存个数(默认300)就像一个网站1000个网页,不用全缓存啊,实时性不高的 访问量特别打大的 适合做缓存
                    'CULL_FREQUENCY': 3,                                      # 缓存到达最大个数之后,剔除缓存个数的比例,把缓存里的老的剔除掉,3 表示三分之一 即:1/CULL_FREQUENCY(默认3)
                },

------------下面这三个不写也行--------
                'KEY_PREFIX': '',                                             # 缓存key的前缀(默认空)
                'VERSION': 1,                                                 # 缓存key的版本(默认1)
                'KEY_FUNCTION' 函数名                                          # 生成key的函数(默认函数会生成为:【前缀:版本:key】)
            }
        }


    # 自定义key
    def default_key_func(key, key_prefix, version):
        """
        Default function to generate keys.

        Constructs the key used by all other methods. By default it prepends
        the `key_prefix'. KEY_FUNCTION can be used to specify an alternate
        function with custom key making behavior.
        """
        return '%s:%s:%s' % (key_prefix, version, key)

    def get_key_func(key_func):
        """
        Function to decide which key function to use.

        Defaults to ``default_key_func``.
        """
        if key_func is not None:
            if callable(key_func):
                return key_func
            else:
                return import_string(key_func)
        return default_key_func
View Code

b、内存

    # 此缓存将内容保存至内存的变量中
    # 配置:
        CACHES = {
            'default': {
                'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',  #主要的改zhe一个
                'LOCATION': 'unique-snowflake',    #这是一个唯一的名称,可以任意指定,但是必须是唯一的(就相当于在内存里创建一个变量,变量名就指向内存的地址)
            }
        }

    # 注:其他配置同开发调试版本
View Code

c、文件

    # 此缓存将内容保存至文件
    # 配置:

        CACHES = {
            'default': {
                'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',  #改这个
                'LOCATION': '/var/tmp/django_cache',  缓存文件的路径,你要把你的东西缓存到哪个位置,放到那,以后再去拿的时候,直接拿开给用户就行了,文件路径下面会生成多个文件
            }
        }
    # 注:其他配置同开发调试版本
View Code

d、数据库

    # 此缓存将内容保存至数据库

    # 配置:
        CACHES = {
            'default': {
                'BACKEND': 'django.core.cache.backends.db.DatabaseCache',
                'LOCATION': 'my_cache_table', # 数据库表
            }
        }

    # 注:执行创建表命令 python manage.py createcachetable执行一下这个命令,执行完这个命令,他就自动帮你在数据库生成一张表,这个表就是专门用来放置缓存的
View Code

e、Memcache缓存(python-memcached模块)这是另外一台机器,有IP有端口

# 此缓存使用python-memcached模块连接memcache

    CACHES = {
        'default': {
            'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
            'LOCATION': '127.0.0.1:11211',    连上那台机器,然后去他的内存里面拿,就行了,指定一下那个机器那个端口
        }
    }
这个软件装上之后,我连上他给他写点东西,我写的时候必须加 键:值,并且还可以加个超时时间,所以我给他写个缓存的时候,我可以给他指定 建是多少,值是多少,超时时间是多少,就写这台机器上了,他就在这台机器是上保存着,怎么保存的呢,他就是普通的字符串,并且保存的时候,值是字符串,键也是字符串而整体的memcache就是一个大字典,每一个键值对就是一个缓存

    CACHES = {
        'default': {
            'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
            'LOCATION': 'unix:/tmp/memcached.sock', 这个就相当于做了一个文件,这个文件就包含了cocket,而你就不用写id写端口了,搞一个文件,通过这个文件给了他他就自动在Unix里面他自动能识别出来,但是这个有限制,只能在本机上面连
        }
    }   

    CACHES = {
        'default': {
            'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
            'LOCATION': [
                '172.19.26.240:11211',
                '172.19.26.242:11211',
            ]加了个列表,列表里面加了多个,这就类似于分布式的了,比如我们有一千个缓存,如果写了他之后,就会把这一千个缓存,在a机器上放一点,在b机器上放一点,两人就分开了,不在放在单机器上了,因为放在单台机器上,可能出现问题,如果这台机器挂了,所有缓存全完了,缓存完蛋了都去数据库拿了,一下数据库压力就变大了,雪崩了 数据库永远起不来了,因为请求一直来,数据库还体不起来,拿到数据量特别大,你的内存肯也不够,你给不了别人,所以就做多台机器
后面可以写成元祖( '172.19.26.240:11211',10)('172.19.26.242:11211',20) 设置权重还是这台机器,别的机器得通过这台机器进行缓存分配,通过这台机器去存的时候给给我一个键 个值 ,你们给了我键之后我会,第一件是把键转化为数字,细算转化成数字,我会根据这个数字,计算出来我到底放在哪个机器上,这个模块它是通过求余数,假如是999除三 是0 我就让他放在这个列表的第0个元素,放到第一台机器上了,但是用户发过来的键是没准生成多少,也许全都命中第一台机器了,别的机器都可少,如果出现这种情况,分布不均了,你要想调整这个平衡,你可以选择设置一些权重,就后面那个值越大,权重越高,怎么设置呢在列表里面多写就行 想20 就复制20遍
        }
    }
View Code

f、Memcache缓存(pylibmc模块)

    # 此缓存使用pylibmc模块连接memcache
    
    CACHES = {
        'default': {
            'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',  #也是memcache模块不一样
            'LOCATION': '127.0.0.1:11211',
        }
    }

    CACHES = {
        'default': {
            'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
            'LOCATION': '/tmp/memcached.sock',
        }
    }   

    CACHES = {
        'default': {
            'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
            'LOCATION': [
                '172.19.26.240:11211',
                '172.19.26.242:11211',
            ]
        }
    }
View Code

   本质上其实都是一样的,放在内存里面的是一个字典对应的键:值,一条键值队就是一个缓存

  文件里的,有文件夹,文件夹里一个个的文件,每个文件就是一个缓存

  放在数据库里的,一个表那就是所有的缓存,一条数据就是一条缓存

 

http://www.cnblogs.com/wupeiqi/articles/5132791.html

2、应用

a、单独视图缓存

        from django.views.decorators.cache import cache_page   先引入一个模块 

        @cache_page(10)     表示我对这个函数进行缓存了,加装饰器 可以设置缓存时间 10 就是10秒
        def my_view(request):
            ...

  
View Code

b、局部视图使用

    a. 引入TemplateTag

        {% load cache %}  这个标签写最上面

    b. 使用缓存

        {% cache 10 缓存key %}
            缓存内容
        {% endcache %}

10 就是19秒
缓存key就是自己起个名字,当键


就比商城里物品的数量不该做缓存,商品介绍就可以做缓存,局部的,就少了页面渲染和数据库请求了
View Code

c. 全站使用

    请求来先走中间件,回的时候也要只走中间件,那我们可以先去缓存里看看有没有缓存,如果有我去缓存里面拿到,直接给你返回就行了,就不会进过视图了,但是要放到最后一个中间件,因为前面的中间件都通过以后代表正确的请求,是按规范操作的。

    我们要想让全站使用缓存得写两个中间件,一个中间件放在最前面,一个放在最后面,请求来要想获取去最后一个获取。而第一个中间件在返回的时候,第一个中间件再去放,所以第一个中间件只有一个 process_response    最后一个中间件也是就一个process_view所以一个中间件里也可以只有一个方法。

    请求来 第一个中间件只有response跳过,最后一个中间去缓存里看,有直接返回,没有就走视图函数,函数走完 跳过view 到前面那个中间有返回,然后给缓存  那个响应给用户
前戏
   使用中间件,经过一系列的认证等操作,如果内容在缓存中存在,则使用FetchFromCacheMiddleware获取内容并返回给用户,当返回给用户之前,判断缓存中是否已经存在,如果不存在则UpdateCacheMiddleware会将缓存保存至缓存,从而实现全站缓存

特殊的中间件 jango写好的,放那就能应运上
    MIDDLEWARE = [
        'django.middleware.cache.UpdateCacheMiddleware',
        # 其他中间件...
        'django.middleware.cache.FetchFromCacheMiddleware',
    ]

这个缓存走的时候就是默认值了,默认300秒,剔除时候剔除三方之一

这个就已近挺牛逼了
  
View Code

 

 

 

 

 

 

 

九、信号

  Django(预留的钩子)在钩子那可以写自己的功能,然后jango在执行的过程中就可以执行咱们写的功能

  这个钩子有多少个呢?

Model signals
    这是钩子的名称,不能改变的
    pre_init                    # django的modal执行其构造方法前,自动触发
    post_init                   # django的modal执行其构造方法后,自动触发  model.userinfo(name="wangk")   或 model.userinfo.objects.create(....) 在内部就是创建构造方法在执行个save
    pre_save                    # django的modal对象保存前,自动触发
    post_save                   # django的modal对象保存后,自动触发   就是save之前和之后
    pre_delete                  # django的modal对象删除前,自动触发
    post_delete                 # django的modal对象删除后,自动触发
    m2m_changed                 # django的modal中使用m2m字段操作第三张表(add,remove,clear)前后,自动触发
    class_prepared              # 程序启动时,检测已注册的app中modal类,对于每一个类,自动触发     在加载每一个类的时候也会触发相应的函数

==================就是Django预留了很多地方让咱们操作,我们还没自定义,就是先找预留了那些==================
Management signals
    pre_migrate                 # 执行migrate命令前,自动触发
    post_migrate                # 执行migrate命令后,自动触发
Request/response signals
    request_started             # 请求到来前,自动触发
    request_finished            # 请求结束后,自动触发 就是HttpResponse前后
    got_request_exception       # 请求异常后,自动触发
Test signals
    setting_changed             # 使用test测试修改配置文件时,自动触发
    template_rendered           # 使用test测试渲染模板时,自动触发
Database Wrappers
    connection_created          # 创建数据库连接时,自动触发

对于Django内部定义的信号,在指定的位置,注入指定的操作(注册这个钩子一定要在程序第一次运行起来的时候注册上,在setting文件上的__init__.py里就行。如果文件太大,在这个文件里在导入到其他文件)

    from django.core.signals import request_finished
    from django.core.signals import request_started
    from django.core.signals import got_request_exception

    from django.db.models.signals import class_prepared
    from django.db.models.signals import pre_init, post_init
    from django.db.models.signals import pre_save, post_save
    from django.db.models.signals import pre_delete, post_delete
    from django.db.models.signals import m2m_changed
    from django.db.models.signals import pre_migrate, post_migrate

    from django.test.signals import setting_changed
    from django.test.signals import template_rendered

    from django.db.backends.signals import connection_created


    def callback(sender, **kwargs):
        print("xxoo_callback")
        print(sender,kwargs)

    xxoo.connect(callback)
    # xxoo指上述导入的内容


 # xxoo指上述导入的内容比如pre_init.connect(callback)

callback就是你定义的那个函数,注册一个钩子

sender是指谁触发的,是jango内部触发的,那这个sender里面包含了jango给咱们提供的一些参数,比如说你当前是对那个model进行操作的,执行model操作的时候,给他传了几个参数,也是都封装在这个参数里面了
View Code

 自定义信号

a. 定义信号

import django.dispatch
pizza_done = django.dispatch.Signal(providing_args=["s", "y"])  这就表示定义了一个信号

你要往我这个信号里注入函数的时候得有两个参数  s   y   

b. 注册信号

def callback(sender, **kwargs):
    print("自定义信号callback")
    print(sender,kwargs)
 
pizza_done.connect(callback)
#执行这个方法,也把函数注入到这个信号里面了,这是不会触发的,因为Django不知道这个信号的存在,Django也不帮你触发,我们得主动的去触发

c. 触发信号

from 路径 import pizza_done     路径找到你的信号
 
pizza_done.send(sender='seven',s=123, y=456)

#pizza_done.send  信号.send  就表示要触发这个信号了
#sender  表示给他传个值,表示谁触发的   后面可以给他加额外的参数
#触发得写在对应的视图函数那

什么时候用自定义信号呢?比如你设计到某一个地方的时候,这个地方以后可能会有各种各样的扩展(比如以前提醒消息,邮箱短信,后来又有了微信,其他)

 

posted @ 2018-10-17 14:27  取经之路  阅读(108)  评论(0)    收藏  举报