django简介下(完结)

首先来说一下数据库的设计三大范式,那么在介绍这个概念之前我们又不得不提到数据库事务ACID
那么ACID分别是原子性、一致性、隔离性、持久性
原子性:最小单位,无法再进行分割
一致性:在开始到结束都不会发生改变
隔离性:多个操作同时进行,不会对数据产生影响
持久性:一旦事务完成则永久生效
根据事务的特性我们总结了数据库设计的三大范式:
第一范式:(类似于原子性)我们所设计的字段都应该是最小字段不可再继续拆分,比如我们设计了地址字段,但是发现对于详细地址具体到省市查询频率都特别高,那么 我们应该将地址拆分才更加合理
第二范式:所有字段都应该与主键有强烈关联,用比较官方的话来说就是主键和非主键遵循完全函数依赖关系
第三范式:其余字段除了与主键有关联之外,相互之间应该是都没有任何关联的即非主键列之间没有传递函数依赖关系。

Ajax:Ajax不是一门新的编程语言而是一种使用现有标准的新方法(可以类比装饰器来看),其最大优点就是不重新加载页面的情况下与服务器交换数据并且更新部分网页也 就是异步提交,局部刷新。
朝后端发送请求的方式
1.浏览器地址栏直接输入url回车 GET请求
2.a标签href属性 GET请求
3.form表单 GET请求/POST请求
4.ajax GET请求/POST请求
Ajax我们只介绍jQuery封装之后的版本(不学原生的 原生的复杂并且在实际项目中也一般不用),所以我们在前端页面使用ajax的时候需要确保导入了jQuery。
基本语法:
$.ajax({
url:"",提交地址,不填写默认本页面提交
type:"post", 提交方式都是小写 默认是get提交
data:{}, 提交数据是字典格式
success:function (){
异步提交的回调机制
}
})
前端向后端提交数据格式:

get向后端提交数据是直接放在url后面:url?username=jason&password=123
那么post呢?首先我们目前接触的能够post提交信息的有两种方式 form表单和ajax
那么我们首先来看form表单,大家可以从浏览器检查的窗口中的network看到前后端交互的过程。

form表单post提交的时候默认提交格式是urlencoded 具体长这个样子username=jason&password=123,但是我们后端拿到数据的时候并不长这个样子,那是因为django的后端会帮你解析封装到request.POST中
我们就可以通过request.POST来拿到这个数据了。

当我们entype设置为formdata用来传输文件数据的时候又是什么样的呢?
如果我们把编码格式改为formdata那么针对普通的键值对还是解析到reque.POST中而将文件解析到request.Files中
form表单是无法json格式数据的。

ajax使用post提交数据的时候默认编码格式也是urlencoded样子与上述一样,因为格式一样,所以django也还是会将数据解析封装到request.POST中
我们在这里要着重介绍一下ajax发送json数据,首先在这里强调我们在传输数据的时候要保证真是一致,也就是说不要说传输的是json实际上不是

首先介绍前端的写法:

$.ajax({
                                    url:"",提交地址,不填写默认本页面提交
                                    type:"post", 提交方式都是小写 默认是get提交
                                    data:{},  提交数据是字典格式
                                    contentType:"application/json", 指定编码格式
                                    success:function (){
                                        异步提交的回调机制            
                                    }
                                    })

然后说一下后端的问题,我们发现当我们以json格式发数据的时候我们没办法从request.POST中获取他们了,我们应该去request.body中取获取
我们会得到一个二进制形式的json格式化的数据
json_bytes = request.body
json_str = json_bytes.decode('utf-8')
json_dict = json.loads(json_str)
接下来我们来了解ajax发送文件格式的数据,ajax发送文件需要借助js内置对象FormData

<script>
                        // 点击按钮朝后端发送普通键值对和文件数据
                        $('#d4').on('click',function () {
                            // 1 需要先利用FormData内置对象
                            let formDateObj = new FormData();
                            // 2 添加普通的键值对
                            formDateObj.append('username',$('#d1').val());
                            formDateObj.append('password',$('#d2').val());
                            // 3 添加文件对象
                            formDateObj.append('myfile',$('#d3')[0].files[0])
                            // 4 将对象基于ajax发送给后端
                            $.ajax({
                                url:'',
                                type:'post',
                                data:formDateObj,  // 直接将对象放在data后面即可

                                // ajax发送文件必须要指定的两个参数
                                contentType:false,  // 不需使用任何编码 django后端能够自动识别formdata对象
                                processData:false,  // 告诉你的浏览器不要对你的数据进行任何处理

                                success:function (args) {
                                }
                            })
                        })
                    </script>

jango自带的序列化组件:
大多数时候我们后期的编程是前后端分离的,即我们只需要写前端获取数据然后渲染或者我们只需要写后端来发送数据,那么现在针对前段所需数据格式我需要列表套字典的格式获取所有表中数据,且表中数据要键值对的格式。
第一种我们可以for循环取出数据然后手动放置在字典中在转为json格式,这种方法在字段数较少的时候还算可以(不考虑代码冗余问题)
第二种使用django自带的序列化组件
from django.core import serializers
res = serializers.serialize('json',user_queryset) 只需要传入转换格式以及数据对象即可,会自动转为json格式的字符串且较为全面
ajax结合sweetalert:
在这里我们使用的sweetalter是bootstrap上的格式,所以我们需要导入sweetalert的css与js文件同时也需要bootstrap的js css文件
https://lipis.github.io/bootstrap-sweetalert/ 样式网站

 $('#b1').on('click',function () {
                                   
                                        let currentBtn = $(this);
                                      
                                       swal({
                                          title: "确定要删除?",
                                          text: "你现在正在删除数据库中数据,你可想好了",
                                          type: "warning",
                                          showCancelButton: true,
                                          confirmButtonClass: "btn-danger",
                                          confirmButtonText: "是的老子就要删!",
                                          cancelButtonText: "算了我是怂逼!",
                                          closeOnConfirm: false,
                                          closeOnCancel: false
                                        },
                                        function(isConfirm) {
                                          if (isConfirm) {
                                           $.ajax({
                                               url:"",
                                               type:"post",
                                               data:{"data":"成功了"},
                                               success:function () {
                                                swal("成功!", "干几把毛害怕了吧", "success");
                                                $("#d1").val("改变了");
                                               }
                                          })


                                          } else {
                                            swal("怂逼", "啥也不是兄弟", "error");
                                          }
                                        })})

批量插入:当想要批量插入数据的时候可以使用orm提供的bulk_create能减少操作时间
      model.Book.object.bulk_create(列表)
分页器:我们在这里值介绍基本逻辑,然后我们会使用已经封装好的代码来使用
    我们获取总共的数据数量后根据数据条数划分页数以及每页数据数量,最后封装进bootstrap已经设计好的模板中

class Pagination(object):
                def __init__(self, current_page, all_count, per_page_num=2, pager_count=11):
                    """
                    封装分页相关数据
                    :param current_page: 当前页
                    :param all_count:    数据库中的数据总条数
                    :param per_page_num: 每页显示的数据条数
                    :param pager_count:  最多显示的页码个数
                    """
                    try:
                        current_page = int(current_page)
                    except Exception as e:
                        current_page = 1

                    if current_page < 1:
                        current_page = 1

                    self.current_page = current_page

                    self.all_count = all_count
                    self.per_page_num = per_page_num

                    # 总页码
                    all_pager, tmp = divmod(all_count, per_page_num)
                    if tmp:
                        all_pager += 1
                    self.all_pager = all_pager

                    self.pager_count = pager_count
                    self.pager_count_half = int((pager_count - 1) / 2)

                @property
                def start(self):
                    return (self.current_page - 1) * self.per_page_num

                @property
                def end(self):
                    return self.current_page * self.per_page_num

                def page_html(self):
                    # 如果总页码 < 11个:
                    if self.all_pager <= self.pager_count:
                        pager_start = 1
                        pager_end = self.all_pager + 1
                    # 总页码  > 11
                    else:
                        # 当前页如果<=页面上最多显示11/2个页码
                        if self.current_page <= self.pager_count_half:
                            pager_start = 1
                            pager_end = self.pager_count + 1

                        # 当前页大于5
                        else:
                            # 页码翻到最后
                            if (self.current_page + self.pager_count_half) > self.all_pager:
                                pager_end = self.all_pager + 1
                                pager_start = self.all_pager - self.pager_count + 1
                            else:
                                pager_start = self.current_page - self.pager_count_half
                                pager_end = self.current_page + self.pager_count_half + 1

                    page_html_list = []
                    # 添加前面的nav和ul标签
                    page_html_list.append('''
                                <nav aria-label='Page navigation>'
                                <ul class='pagination'>
                            ''')
                    first_page = '<li><a href="?page=%s">首页</a></li>' % (1)
                    page_html_list.append(first_page)

                    if self.current_page <= 1:
                        prev_page = '<li class="disabled"><a href="#">上一页</a></li>'
                    else:
                        prev_page = '<li><a href="?page=%s">上一页</a></li>' % (self.current_page - 1,)

                    page_html_list.append(prev_page)

                    for i in range(pager_start, pager_end):
                        if i == self.current_page:
                            temp = '<li class="active"><a href="?page=%s">%s</a></li>' % (i, i,)
                        else:
                            temp = '<li><a href="?page=%s">%s</a></li>' % (i, i,)
                        page_html_list.append(temp)

                    if self.current_page >= self.all_pager:
                        next_page = '<li class="disabled"><a href="#">下一页</a></li>'
                    else:
                        next_page = '<li><a href="?page=%s">下一页</a></li>' % (self.current_page + 1,)
                    page_html_list.append(next_page)

                    last_page = '<li><a href="?page=%s">尾页</a></li>' % (self.all_pager,)
                    page_html_list.append(last_page)
                    # 尾部添加标签
                    page_html_list.append('''
                                                       </nav>
                                                       </ul>
                                                   ''')
                    return ''.join(page_html_list)

使用:
1.传值生成对象
page_obj = Pagination(current_page=current_page,all_count=all_count)
2 直接对总数据进行切片操作
page_queryset = book_queryset[page_obj.start:page_obj.end]
这就是类似于你平常使用的模块,你可以import导入他,这个自定义的模块不用再使用前端渲染,bootstrap的代码也在其中

form表单校验:我们除了要在前端进行数据验证之外在后端也要进行数据的验证,因为前端的验证并不是可靠的。为此django为我们提供了一个 实用的模块form组件校验数据。
from django import forms
class 类名(forms.Form):
username = forms.CharFiled(min_length,max_length)
我们可以使用pycharm为我们准备的django测试环境 python console
from app01 import views
1 将带校验的数据组织成字典的形式传入即可
form_obj = views.MyForm({'username':'jason','password':'123','email':'123'})
2 判断数据是否合法 注意该方法只有在所有的数据全部合法的情况下才会返回True
form_obj.is_valid()
False
3 查看所有校验通过的数据
form_obj.cleaned_data
{'username': 'jason', 'password': '123'}
4 查看所有不符合校验规则以及不符合的原因
form_obj.errors
{
'email': ['Enter a valid email address.']
}
5 校验数据只校验类中出现的字段 多传不影响 多传的字段直接忽略
form_obj = views.MyForm({'username':'jason','password':'123','email':'123@qq.com','hobby':'study'})
form_obj.is_valid()
True
6 校验数据 默认情况下 类里面所有的字段都必须传值
form_obj = views.MyForm({'username':'jason','password':'123'})
form_obj.is_valid()
False

也就意味着校验数据的时候 默认情况下数据可以多传但是绝不可能少传

渲染标签: 后端先生成一个空对象
第一种渲染方式{{form_obj.as_p}} 封装程度高不易于扩展 同时不会帮你渲染button按钮
第二种{{form_obj.label}}:{{form_obj.username}} 虽然这种方法我们扩展性变高了,但是多个字段要写多个所以...
第三种 {% for form in form_obj %}
<p>{{ form.label }}:{{ form }}</p>
{% endfor %}
label是对应的字段中的名字,我们可以自己进行设置
展示校验信息:
如何让浏览器不做校验
<form action="" method="post" novalidate>

def index(request):
                    # 1 先产生一个空对象
                    form_obj = MyForm()
                    if request.method == 'POST':
                        # 获取用户数据并且校验
                        """
                        1.数据获取繁琐
                        2.校验数据需要构造成字典的格式传入才行
                        ps:但是request.POST可以看成就是一个字典
                        """
                        # 3.校验数据
                        form_obj = MyForm(request.POST)
                        # 4.判断数据是否合法
                        if form_obj.is_valid():
                            # 5.如果合法 操作数据库存储数据
                            return HttpResponse('OK')
                        # 5.不合法 有错误
                    # 2 直接将该空对象传递给html页面
                    return render(request,'index.html',locals())

                {% for form in form_obj %}
                        <p>
                            {{ form.label }}:{{ form }}
                            <span style="color: red">{{ form.errors.0 }}</span>
                        </p>
                {% endfor %}

"""
1.必备的条件 get请求和post传给html页面对象变量名必须一样
2.forms组件当你的数据不合法的情况下 会保存你上次的数据 让你基于之前的结果进行修改
更加的人性化
"""
# 针对错误的提示信息还可以自己自定制

class MyForm(forms.Form):
                    # username字符串类型最小3位最大8位
                    username = forms.CharField(min_length=3,max_length=8,label='用户名',
                                               error_messages={
                                                   'min_length':'用户名最少3位',
                                                   'max_length':'用户名最大8位',
                                                   'required':"用户名不能为空"
                                               }
                                               )
                    # password字符串类型最小3位最大8位
                    password = forms.CharField(min_length=3,max_length=8,label='密码',
                                               error_messages={
                                                   'min_length': '密码最少3位',
                                                   'max_length': '密码最大8位',
                                                   'required': "密码不能为空"
                                               }
                                               )
                    # email字段必须符合邮箱格式  xxx@xx.com
                    email = forms.EmailField(label='邮箱',
                                             error_messages={
                                                 'invalid':'邮箱格式不正确',
                                                 'required': "邮箱不能为空"
                                             }
                                             )

钩子函数:在特定的节点自动触发完成相应操作
在form组件中有两类钩子局部和全局钩子,他们扮演这第二道关卡,让我们自定义校验规则
局部:当你需要给某个字段加校验规则的时候使用
def clean_username(self):
# 获取到用户名
username = self.cleaned_data.get('username')
if '666' in username:
# 提示前端展示错误信息
self.add_error('username','光喊666是不行滴~')
# 将钩子函数钩去出来数据再放回去
return username
全局:当你需要给多个字段加校验规则的时候使用
def clean(self):
password = self.cleaned_data.get('password')
confirm_password = self.cleaned_data.get('confirm_password')
if not confirm_password == password:
self.add_error('confirm_password','两次密码不一致')
# 将钩子函数钩出来数据再放回去
return self.cleaned_data
forms组件其他参数及补充知识点
label 字段名
error_messages 自定义报错信息
initial 默认值
required 控制字段是否必填
widget=forms.widgets.PasswordInput(attrs={'class':'form-control c1 c2'})
多个属性值的话 直接空格隔开即可

第一道关卡里面还支持正则校验,多个正则依次校验
validators=[
RegexValidator(r'^[0-9]+$', '请输入数字'),
RegexValidator(r'^159[0-9]+$', '数字必须以159开头')
]
其他类型渲染

# radio
                    gender = forms.ChoiceField(
                        choices=((1, ""), (2, ""), (3, "保密")),
                        label="性别",
                        initial=3,
                        widget=forms.widgets.RadioSelect()
                    )
                    # select
                    hobby = forms.ChoiceField(
                        choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
                        label="爱好",
                        initial=3,
                        widget=forms.widgets.Select()
                    )
                    # 多选
                    hobby1 = forms.MultipleChoiceField(
                        choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
                        label="爱好",
                        initial=[1, 3],
                        widget=forms.widgets.SelectMultiple()
                    )
                    # 单选checkbox
                    keep = forms.ChoiceField(
                        label="是否记住密码",
                        initial="checked",
                        widget=forms.widgets.CheckboxInput()
                    )
                    # 多选checkbox
                    hobby2 = forms.MultipleChoiceField(
                        choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
                        label="爱好",
                        initial=[1, 3],
                        widget=forms.widgets.CheckboxSelectMultiple()
                    )

COOKIE与session:我们发现在我们使用的许多网站上都是会记录用户的登录状态的,当你进行第一次登陆之后很多情况下就不用再次登陆了,这个功能的实现就要归功于COOKIE与session了。

cookie
服务端保存在客户端浏览器上的信息都可以称之为cookie
它的表现形式一般都是k:v键值对(可以有多个)
session
数据是保存在服务端的并且它的表现形式一般也是k:v键值对(可以有多个)

COOKIE操作:如果想要操作COOKIE就不得不利用obj对象来操作
obj1 = HttpResponse()
return obj1

obj2 = render()
return obj2

obj3 = redirect()
return obj3
设置cookie obj.set_cookie(key,value)
获取cookie request.COOKIES.get(key)
在设置cookie的时候可以添加一个超时时间obj.set_cookie(...,max_age=3)
注销功能就是删除COOKIE obj.delete_cookie("username")
cookie完成用户登录

def login_auth(func):
    def inner(request,*args,**kwargs):
        before_url = request.get_full_path()
        print(before_url)
        if request.COOKIES.get("username"):
            return func(request,*args,**kwargs)
        else:
            return redirect('/app01/login/?next=%s'%before_url)
    return inner

    def login(request):
        if request.method == 'POST':
            username = request.POST.get("username")
            password = request.POST.get("password")
            before_url = request.GET.get("next")
            obj = redirect(before_url)
            obj.set_cookie("username",username)
            return obj
        return render(request,"login.html")
    @login_auth
    def index(request):
        return HttpResponse("this is index")

session操作:session数据是保存在服务端的,给客户端返回的是随机字符串
在默认情况下操作session的时候需要django默认的一张django_session表,在进行数据库迁移的时候会自动创建
默认失效时间是14天,也可以人为修改
django_session表数据条数是取决于浏览器的,同一个计算机上同一个浏览器只会有一套数据
设置session request.session["key"] = value
内部发生了什么:
1.django内部会自动帮你生成一个随机字符串
2.存储字符串和相应数据(这一步不是直接生效而是拆分成了两步,现在内存中产生操作数据的缓存,在经过中间键的时候才去操作数据库)
3.将产生的随机字符串返回给浏览器保存
获取session request.session.get("key")
内部发生了什么:
1.自动从浏览器请求中获取sessionid对应的随机字符串
2.与django_session表中查找对应数据
3.如果比对成功 将对应数据取出以字典的形式封装到request.session中
如果不对不上返回none
设置过期时间 request.session.set_expiry(内部有四种类型参数 整数对应秒数 日期对象 0对应一旦浏览器窗口关闭就失效 不写失效时间取决于默认)
清除session
request.session.delete()
request.session.flush() 双端全清空

session实现用户登录验证:
        def login_auth(func):
            def inner(request,*args,**kwargs):
                before_url = request.get_full_path()
                if request.session.get("username"):
                    print("获取到了",request.session.get("username"))
                    res = func(request,*args,**kwargs)
                    return res
                else:
                    print("没获取到")
                    return redirect("/app01/login/?next=%s"%before_url)
            return inner

        def login(request):
            if request.method == "POST":
                username = request.POST.get("username")
                password = request.POST.get("password")
                before_url = request.GET.get("next")
                print(before_url,username,type(username))
                obj = redirect(before_url)
                request.session["username"] = username@
                print(request.session.get("username"))
                return obj
            return render(request,"login.html")

        @login_auth
        def index(request):
            return HttpResponse("index")

CBV函数实现装饰器的使用:

from django.utils.decorators import method_decorator
                    # @method_decorator(login_auth,name='get')  # 方式2(可以添加多个针对不同的方法加不同的装饰器)
                    # @method_decorator(login_auth,name='post')
                    class MyLogin(View):
                        @method_decorator(login_auth)  # 方式3:它会直接作用于当前类里面的所有的方法
                        def dispatch(self, request, *args, **kwargs):
                            return super().dispatch(request,*args,**kwargs)
                        # @method_decorator(login_auth)  # 方式1:指名道姓
                        def get(self,request):
                            return HttpResponse("get请求")

                        def post(self,request):
                            return HttpResponse('post请求')

django中间件:作为django的门户,请求来响应出去都需要经过中间件,django默认有七个中间件
我们通过观察django默认中间件的源码可以发现他们共同的方法是process_request和process_response
当我们自定义中间件的时候也需要这些方法

django支持程序员自定义中间件并且暴露给程序员五个可以自定义的方法
1.必须掌握
process_request
process_response
2.了解即可
process_view
process_template_response
process_exception
1.在项目名或者应用名下创建一个任意名称的文件夹
2.在该文件夹内创建一个任意名称的py文件
3.在该py文件内需要书写类(这个类必须继承MiddlewareMixin)
然后在这个类里面就可以自定义五个方法了
(这五个方法并不是全部都需要书写,用几个写几个)
4.需要将类的路径以字符串的形式注册到配置文件中才能生效

process_request方法:
1.请求来的时候需要经过每一个中间件的process_request方法,顺序是注册文件的从上向下顺序
2.如果中间件没有定义上述方法,那么跳过这个中间件
3.如果方法返回了HTTPResponse对象,那么请求直接返回了不在向下走
process_response方法:
1.响应走的时候需要经过每一个中间件的process_response方法,顺序是注册文件的从下向上顺序
2.方法必须返回一个HTTPResponse对象
3.如果没有该方法则跳过这个中间件

如果在第一个process_request就返回了一个HTTPResponse对象,那么响应走的时候会直接走同一级的process_response返回
process_view
路由匹配成功之后执行视图函数之前,会自动执行中间件里面的该放法
顺序是按照配置文件中注册的中间件从上往下的顺序依次执行

process_template_response
返回的HttpResponse对象有render属性的时候才会触发
顺序是按照配置文件中注册了的中间件从下往上依次经过

process_exception
当视图函数中出现异常的情况下触发
顺序是按照配置文件中注册了的中间件从下往上依次经过

csrf跨站请求伪造:钓鱼网站 本质上就是提供给用户的某个接口是没有属性值的类似于一个没有接上电源的按钮,当用户发送请 求的时候我们会将我们事先设置好的信息连同用户信息给目标网站发过去,从而达到我们想要的效果
那么我们如何避免这种情况呢?
网站在给用户返回一个具有提交数据功能页面的时候会给这个页面加一个唯一标识
当这个页面朝后端发送post请求的时候 我的后端会先校验唯一标识,如果唯一标识不对直接拒绝(403 forbbiden)如果成功则正常执行
form表单如何符合校验:需要在form表单内加上一个{%csrf token%}
ajax 如何校验

// 第一种 利用标签查找获取页面上的随机字符串
                {#data:{"username":'jason','csrfmiddlewaretoken':$('[name =csrfmiddlewaretoken]').val()},#}
                // 第二种 利用模版语法提供的快捷书写
                {#data:{"username":'jason','csrfmiddlewaretoken':'{{ csrf_token }}'},#}
                // 第三种 通用方式直接拷贝js代码并应用到自己的html页面上即可
                function getCookie(name) {
                var cookieValue = null;
                if (document.cookie && document.cookie !== '') {
                    var cookies = document.cookie.split(';');
                    for (var i = 0; i < cookies.length; i++) {
                        var cookie = jQuery.trim(cookies[i]);
                        // Does this cookie string begin with the name we want?
                        if (cookie.substring(0, name.length + 1) === (name + '=')) {
                            cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                            break;
                        }
                    }
                }
                return cookieValue;
            }
            var csrftoken = getCookie('csrftoken');


            function csrfSafeMethod(method) {
              // these HTTP methods do not require CSRF protection
              return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
            }

            $.ajaxSetup({
              beforeSend: function (xhr, settings) {
                if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
                  xhr.setRequestHeader("X-CSRFToken", csrftoken);
                }
              }
            });

srf相关装饰器:
from django.views.decorators.csrf import csrf_protect,csrf_exempt
from django.utils.decorators import method_decorator
1.网站整体不校验,校验部分csrf_protcet
2.网站整体校验,不校验部分csrf_exempt
对于CBV装饰器使用上有一些不同
protect第一种指名道姓的可行第二种整体的也可以第三种继承dispatch也可行
exempt第一种指名道姓的不可行第二种整体的也不可以第三种可行

settings思想:在介绍settings思想之前先补充一个知识点import_lib模块
importlib:字符串导入模块 importlib.import_module(str)最小只能到py文件名
接下来我们来介绍一下django中settings设置的一种思想
首先我们看到的django中的settings文件是这样的,

我们可以通过注释一段字符串来使该方法在全局都生效或者失效,那么这是如何做到的呢?
首先我们将所需的功能设计成对象的形式,也就是设计成类,然后将多个文件封装到一个包内,给包设置一个__init__文件,
然后创建我们自己的settings文件以及启动文件start,按照django的格式将字符串设置到setting文件里
接下来设置__init__文件,获取路径然后进行切片获得字符串形式的模块路径和类名,利用反射获得类的真实名字,生成类的对象,然后根据鸭子类型调用实际方法。

auth模块:
我们在创建好一个django项目之后直接执行数据库迁移命令会自动生成很多表。
django启动之后可以直接访问admin路由 参考的就是自动创建的auth_user表

首先我们来创建管理员用户 createsuperuser 通过auth_user表能够完成许多操作,让我们一个个来探索
依赖于auth_user表完成用户相关功能
from django.contrib import auth 导入auth模块
1.auth.authenticate(request,username = username,password = password) 自动查找auth_user表 给密码加密并比对,这个方法必须同时传入两个参数,必须两个同时传,正确的话返回结果是一个用户对象如果不正确返回一个None
2.auth.login(request,res) 保存用户登录状态,类似于session操作,只要执行了该方法你就可以在任何地方通过request.user获取当前登录的用户对象,本质就是去django的session表中自动查找,然后将结果封装到request.user中,当session中没有对象的时候会返回一个匿名用户,可以通过request.user.is_authenticated()判断用户是否登录
3. from django.contrib.auth.decorators import login_required
@login_required(login_url="/login/")
验证用户是否登录的一个装饰器,与我们自己之前手动敲的装饰器方法类似,通过设置参数来设置跳转位置,这样设置是局部配置,你可以通过设置settings来进行全局设置。
如果全局和局部同时存在,那么局部优先使用
4.request.user.check_password(password)自动加密比对密码,返回布尔值
request.user.set_password(new_password)修改密码 需要save一下才能真正更改密码
5.auth.logout(request)注销功能,就相当于session.flush
6.from django.contrib.auth.models import User 导入之后相当于获取了这张auth_user表
当我们使用orm语句的时候我们添加的用户密码是明文的,之后的auth方法都失效了,因为密码是明文
创建普通用户: User.objects.create_user(username = username,password = password)
创建管理员用户(超级用户):User.objects.create_superuser(username = username,password = password,email = xxx)
这个位置邮箱字段是必填的


如何扩展auth_user表:当我们需要扩展user表的字段的时候我们应该怎么做呢?
第一种方式:onetoonefiled 我们可以关联一个第三方表来增加字段
第二种利用面向对象的继承:说到这个方法我们就应该来看一下User表的本质了,

User本身是什么都没有的,他的所有东西都是继承来的,那么我们也可以通过继承来完成我们的需求
class UserInfo(AbstractUser): 我们再这样设置之后进行数据库迁移,auth_user表就不会被建立,取而代之的是userinfo表,它包含了auth_user中所有字段以及我们自定义的字段
前提:1.执行之前没有进行数据库迁移,也就是本身是没有auth_user表的
2.不要覆盖AbstractUser的字段
3.需要在配置文件中声明用userinfo替换auth_userAUTH_USER_MODEL = "应用名.表名"

django的学习就告一段落了,不知道小伙伴们的掌握情况怎么样 接下来会联系一个bbs项目,希望大家也动手做一做

posted @ 2020-06-09 23:09  TopJocker  阅读(251)  评论(0编辑  收藏  举报