为您推荐:
精华内容
最热下载
问答
  • 5星
    2.22MB weixin_40228600 2021-02-22 10:22:02
  • 5星
    3.63MB agelee 2021-10-12 14:56:26
  • 5星
    17.55MB qq_31899125 2021-05-22 21:52:40
  • 5星
    6.25MB bala5569 2021-03-06 10:01:26
  • 5星
    241KB weixin_54707168 2021-06-18 15:22:43
  • Python之django进阶 文章目录Python之django进阶一、批量插入数据二、分页类的使用三、cookie介绍1、什么是cookie2、cookie的原理3、cookie版验证登录4、关于cookie的更多操作四、session介绍1、session相关方法2、...

    Python之django进阶

    一、批量插入数据

    • bulk_create()
    def pl_insert(request):
        for i in range(10000):
            models.user.objects.create(title='第%s行'%i)
        data_all = models.user.objects.all()
        return render(request,'all.html',locals())
    """
    上述代码执行时将近耗时8秒多(很可怕,这才一万条数据)
    """
    def pl_insert(request):
        pl_list = []
        for i in range(100000):
            pl_obj = models.user(title='第%s行'%i)
            pl_list.append(pl_obj)
        data_all = models.user.bulk_create(pl_list)
        return render(request,'all.html',locals())
    """
    第二种代码只运行了三秒(效果非常好)
    """
    # 总结:在批量插入数据时可以使用orm提供的fulk_create()来减少操作时间
    

    二、分页类的使用

    • 在左侧栏新建lib文件夹将以下代码放置到一个py文件中
    class Pagination(object):
        def __init__(self, current_page, all_count, per_page_num=10, 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)
    
    • 后端操作
    from lib.mypage import Pagination
    def booklist(request):
        # 算出所有数据的总条数
        all_count = models.book.objects.count()
        # 拿到当前是那一页
        current_page = request.GET.get('page',1)
        # 调用分页库
        obj = Pagination(current_page,all_count)
        # 传给前端html格式
        page_html = obj.page_html()
        # 取出数据的开始和结束
        all_data = models.book.objects.all()[obj.start:obj.end]
    
        return render(request,'booklist.html',locals())
    
    • 前端操作
    {% for foo in all_data %}
    
        <p style="align-content: center">
            {{ foo.title }}
        </p>
    {% endfor %}
    
    {{ page_html|safe }}
    

    三、cookie介绍

    1、什么是cookie

    Cookie具体指的是一段小信息,它是服务器发送出来存储在浏览器上的一组组键值对,下次访问服务器时浏览器会自动携带这些键值对,以便服务器提取有用信息。
    

    2、cookie的原理

    cookie的工作原理是:由服务器产生内容,浏览器收到请求后保存在本地;当浏览器再次访问时,浏览器会自动带上Cookie,这样服务器就能通过Cookie的内容来判断这个是“谁”了。
    

    3、cookie版验证登录

    • 前端代码
    login_cookie.html
    <div style="width:100%;text-align:center" class="center">
        <form action="" METHOD="post" >
        <p>
            username:<input type="text" name="username" >
        </p>
        <p>
            password:<input type="password" name="password">
        </p>
    
        <input type="submit" class="btn btn-success" id="button">
    </form>
    </div>
    home_cookie.html
    <h1>你好,我是登录后的页面~(cookie)</h1>
    <a href="/del_session/" class="btn btn-danger">退出登录</a>
    
    • 后端代码
    from django.shortcuts import render,HttpResponse,redirect
    # Create your views here.
    
    """
    cookie版验证登录
    """
    # 登陆装饰器
    def login_auth_cookie(func):
        def inner(request,*args,**kwargs):
            path = request.get_full_path()
            """
            检测用户当前路径,用于用户点击其他页面也需要用户登录
            """
            if request.COOKIES.get('key'): # 这里使用request.COOKIES.get判断用户到底是否登录
                return func(request,*args,**kwargs)
            else:
                # 用户没有登录,其先前点击的路径将会拼接到登录页面的后面
                return redirect('/login/?next=%s'%path)
        return inner
    
    
    def login_cookie(request):
        if request.method =='POST':
            username = request.POST.get('username')
            password = request.POST.get('password')
            if username == 'egon' and password == '123':
                print(username,password)
                next = request.GET.get('next') # 获取用户/login/后面的路径
                if next:
                    # 用户一旦登录跳转至用户之前打开位置的网址
                    res = redirect(next)
                    res.set_cookie(key='key', value='123')
                else:
                    # 用户没有点击其他网页跳转会首页网页
                    res = redirect('/home_cookie/')
                    res.set_cookie(key='key', value='123')
                return res
        # 用户密码有误或者不登录将一直在登陆页面
        return render(request, 'login_cookie.html')
    
    # 登录成功后所实现的页面的方法
    @login_auth_cookie
    def home_cookie(request):
        return render(request, 'home_cookie.html')
    
    # 验证装饰器及其非登录进入页面检测路径的方法
    @login_auth_cookie
    def index_cookie(request):
        return HttpResponse('这里是index页面(cookie)')
    
    # 用户退出后,清除cookie的方法
    def del_cookie(request):
        res = redirect('/login_cookie/')
        res.delete_cookie('key')
        return res
    

    4、关于cookie的更多操作

    获取cookie

    request.COOKIES['key']
    request.get_signed_cookie(key, default=RAISE_ERROR, salt='', max_age=None)
    # 参数
    	default:默认值
        salt:加密盐
        max_age:后台控制时间
    

    设置cookie

    rep = HttpResponse(...)
    rep = render(request, ...)
    
    rep.set_cookie(key,value,...)
    rep.set_signed_cookie(key,value,salt='加密盐', max_age=None, ...)
    """
    key:键
    value:值
    max_age=None 超时时间
    expires=None, 超时时间(IE requires expires, so set it if hasn't been already.)
    path='/', Cookie生效的路径,/ 表示根路径,特殊的:根路径的cookie可以被任何url的页面访问
    domain=None, Cookie生效的域名
    secure=False, https传输
    httponly=False 只能http协议传输,无法被JavaScript获取(不是绝对,底层抓包可以获取到也可以被覆盖)
    """
    

    删除cookie

    def logout(request):
        rep = redirect("/login/")
        rep.delete_cookie("user")  # 删除用户浏览器上之前设置的usercookie值
        return rep
    

    四、session介绍

    1、session相关方法

    # 获取、设置、删除Session中数据
    request.session['k1']
    request.session.get('k1',None)
    request.session['k1'] = 123
    request.session.setdefault('k1',123) # 存在则不设置
    del request.session['k1']
    
    
    # 所有 键、值、键值对
    request.session.keys()
    request.session.values()
    request.session.items()
    request.session.iterkeys()
    request.session.itervalues()
    request.session.iteritems()
    
    # 会话session的key
    request.session.session_key
    
    # 将所有Session失效日期小于当前日期的数据删除
    request.session.clear_expired()
    
    # 检查会话session的key在数据库中是否存在
    request.session.exists("session_key")
    
    # 删除当前会话的所有Session数据
    request.session.delete()
      
    # 删除当前的会话数据并删除会话的Cookie。
    request.session.flush() 
        这用于确保前面的会话数据不可以再次被用户的浏览器访问
        例如,django.contrib.auth.logout() 函数中就会调用它。
    
    # 设置会话Session和Cookie的超时时间
    request.session.set_expiry(value)
        * 如果value是个整数,session会在些秒数后失效。
        * 如果value是个datatime或timedelta,session就会在这个时间后失效。
        * 如果value是0,用户关闭浏览器session就会失效。
        * 如果value是None,session会依赖全局session失效策略。
    

    2、session相关解析流程图

    img

    3、session版验证登录

    • 前端代码
    login_session.html
    <div style="width:100%;text-align:center">
        <form action="" method="post">
            <p>
                username:<input type="text" name="username">
            </p>
            <p>
                password:<input type="text" name="password">
            </p>
            <input type="submit" class="btn btn-success">
        </form>
    </div>
    home.html
    <h1>你好,我是登录后的页面~(session)</h1>
    <a href="/del_session/" class="btn btn-danger">退出登录</a>
    
    • 后端代码
    from django.shortcuts import render,HttpResponse,redirect
    # Create your views here.
    
    """
    session版验证登录
    """
    # 登陆装饰器
    def login_auth_session(func):
        def inner(request,*args,**kwargs):
            path = request.get_full_path()
            """
            检测用户当前路径,用于用户点击其他页面也需要用户登录
            """
            if request.session.get('name'): # 这里使用request.session.get('xxx')判断用户到底是否登录
                return func(request,*args,**kwargs)
    
            # 用户没有登录,其先前点击的路径将会拼接到登录页面的后面
            return redirect('/login_session/?next=%s'%path)
        return inner
    
    # 登录页面
    from app01 import models
    def login_session(request):
        if request.method == 'POST':
            username = request.POST.get('username')
            password = request.POST.get('password')
            login_obj = models.user.objects.filter(username=username).first()
            if login_obj:
                if login_obj.password == int(password):
                    request.session['name'] = username
                    next = request.GET.get('next') # 获取用户/login/后面的路径
                    if next:
                        res = redirect(next) # 如果路径存在,登录成功后跳转到该页面
                        return res
                    res = redirect('/home_session/') # 如果路径不存在跳转至首页
                    return res
        # 用户密码有误或者不登录将一直在登陆页面
        return render(request,'login_session.html')
    
    
    # 登录成功后所实现的页面的方法
    @login_auth_session
    def home_session(request):
        return render(request,'home_session.html')
    
    
    # 验证装饰器及其非登录进入页面检测路径的方法
    @login_auth_session
    def index_session(request ):
        return HttpResponse('我是通过装饰器登录的页面')
    
    
    # 用户点击退出登录,清除session的方法
    def del_session(request):
        request.session.flush() # 清空客户端和服务端(推荐)
        request.session.delete()  # 清空服务端
        return redirect('/login_session/')
    

    五、CBV版添加装饰器

    在上面的添加装饰器均是在类中添加,那么在views.py视图函数内如何给类添加装饰器?

    CBV版登录认证

    • 后端代码
    from django.views import View
    
    class login_cbv(View):
        def get(self,request):
            return render(request,'login_cbv.html')
        def post(self,request):
            username = request.POST.get('username')
            password = request.POST.get('password')
            if username == 'egon' and password == '123':
                return HttpResponse('POST请求登录')
            return render(request,'login_cbv.html')
    
    • 前端代码
    <div style="width:100%;text-align:center">
        <form action="" METHOD="post" >
        <p>
            username:<input type="text" name="username" >
        </p>
        <p>
            password:<input type="password" name="password">
        </p>
    
        <input type="submit" class="btn btn-success" id="button">
    </form>
    </div>
    

    CBV添加装饰器版的登录认证(三种方式)

    # 需要先导入模块
    from django.utils.decorators import method_decorator
    
    • 后端代码
    from django.views import View
    
    # 装饰器
    def login_decor(func):
        def inner(request,*args,**kwargs):
            path = request.get_full_path()
            """
            检测用户当前路径,用于用户点击其他页面也需要用户登录
            """
            if request.session.get('name'):  # 这里使用request.session.get('xxx')判断用户到底是否登录
                return func(request, *args, **kwargs)
    
            # 用户没有登录,其先前点击的路径将会拼接到登录页面的后面
            return redirect('/login_session/?next=%s' % path)
    
        return inner
    
    from django.utils.decorators import method_decorator
    
    """
    直接加在视图类上,但method_decorator必须传 name 关键字参数
    get方法和post方法都需要登录校验的话就写两个装饰器
    """
    # 登录模块
    @method_decorator(login_decor,name='get')
    @method_decorator(login_decor,name='post')
    class login_cbv(View):
        """
        加在dispatch中表示包含在
        http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
        内所有的请求都添加装饰器
        因为CBV中首先执行的就是dispatch方法,所以这么写相当于给get和post方法都加上了登录校验。
        """
        @method_decorator(login_decor)
        def dispatch(self, request, *args, **kwargs):
            return super(login_cbv, self).dispatch(request, *args, **kwargs)
    
        """
        单独加在CBV视图的get或post方法上表示对单个请求加装饰器
        """
        @method_decorator(login_decor)
        def get(self,request):
            return render(request,'login_cbv.html')
    
    
        def post(self,request):
            username = request.POST.get('username')
            password = request.POST.get('password')
            login_obj = models.user.objects.filter(username=username).first()
            if login_obj:
                if login_obj.password == int(password):
                    request.session['name'] = username
                    next = request.GET.get('next')  # 获取用户/login/后面的路径
                    if next:
                        res = redirect(next)  # 如果路径存在,登录成功后跳转到该页面
                        return res
                    res = HttpResponse('POST请求登录')  # 如果路径不存在跳转至首页
                    return res
            return render(request,'login_cbv.html')
    
    
    • 前端代码
    <div style="width:100%;text-align:center">
        <form action="" METHOD="post" >
        <p>
            username:<input type="text" name="username" >
        </p>
        <p>
            password:<input type="password" name="password">
        </p>
    
        <input type="submit" class="btn btn-success" id="button">
    </form>
    </div>
    

    六、中间件

    1、什么是中间件

    在学Django生命周期图的时候,中间件在web网关服务接口与路由层中间,所以我们可以知道当请求来的时候是先走中间件的,后走路由层的。那么我们就能想到,是不是对中间件的操作就能影响路由层与视图层呢?

    官方关于中间件的文档:中间件是一个用来处理Django的请求和响应的框架级别的钩子。它是一个轻量、低级别的插件系统,用于在全局范围内改变Django的输入和输出。每个中间件组件都负责做一些特定的功能。但是由于其影响的是全局,所以需要谨慎使用,使用不当会影响性能

    说的直白一点中间件是帮助我们在视图函数执行之前和执行之后都可以做一些额外的操作,它本质上就是一个自定义类,类中定义了几个方法,Django框架会在请求的特定的时间去执行这些方法。

    这些中间件通常存在与settings文件下的MIDDLEWARE列表内,我们的每一次请求都离不开他们

    MIDDLEWARE = [
        'django.middleware.security.SecurityMiddleware',
        'django.contrib.sessions.middleware.SessionMiddleware',
        'django.middleware.common.CommonMiddleware',
        'django.middleware.csrf.CsrfViewMiddleware',
        'django.contrib.auth.middleware.AuthenticationMiddleware',
        'django.contrib.messages.middleware.MessageMiddleware',
        'django.middleware.clickjacking.XFrameOptionsMiddleware',
    ]
    

    2、自定义中间件

    中间可以自定义的方法有五个(主要掌握process_request和process_response)

    • process_request(self, request)
    • process_response(self, request, response)
    • process_view(self, request, view_func, view_args, view_kwargs)
    • process_template_response(self, request, response)
    • process_exception(self, request, exception)

    上面的方法都可返回None或者Httpresponse对象,如果返回None那么Django将继续向下执行视图层的代码等等。但是如果返回了Httpresponse对象,那么Django将不会继续执行下面路由层及视图层的代码会将Httpresponse对象优先返回给用户

    自定义中间件示例

    """
    首先在项目下建立一个middleware文件夹(名字可以随便起)
    在middleware文件夹内建立一个py文件
    文件内书写以下代码
    """
    from django.utils.deprecation import MiddlewareMixin
    from django.shortcuts import render,HttpResponse,redirect
    
    
    class Mymiddleware1(MiddlewareMixin):
        def process_request(self,request):
            print('这是第一个自定义中间中的process_request')
    
        def process_response(self,request,response):
            print('这是第一个自定义中间中的process_response')
            return HttpResponse('Mymiddleware1')
    
    
    class Mymiddleware2(MiddlewareMixin):
        def process_request(self,request):
            print('这是第二个自定义中间中的process_request')
    
        def process_response(self,request,response):
            print('这是第二个自定义中间中的process_response')
            return HttpResponse('Mymiddleware1')
            
     """
     将此文件导入settings文件内并在MIDDLEWARE内添加以下代码
     """
    MIDDLEWARE = [
        'django.middleware.security.SecurityMiddleware',
        'django.contrib.sessions.middleware.SessionMiddleware',
        'django.middleware.common.CommonMiddleware',
        # 'django.MyMiddleware.csrf.CsrfViewMiddleware',
        'django.contrib.auth.middleware.AuthenticationMiddleware',
        'django.contrib.messages.middleware.MessageMiddleware',
        'django.middleware.clickjacking.XFrameOptionsMiddleware',
        'MyMiddleware.ware.Mymiddleware1', # 自定义中间件1
        'MyMiddleware.ware.Mymiddleware2', # 自定义中间件2
    ]
    
    
    # 此时终端打印结果
    """
    这是第一个自定义中间中的process_request
    这是第二个自定义中间中的process_request
    这是第二个自定义中间中的process_response
    这是第一个自定义中间中的process_response
    """
    由此可以总结出:
    当Http请求来的时候中间件的执行顺序是自上而下执行
    当后端给返回浏览器响应数据时中间件是自上而下执行
    

    3、process_request

    process_request(self, request)有个参数request,这个request和视图函数中request是一样的(在交给Django后端的路由之前,对这个request对象可以进行一系列操作)

    由于request对象是一样的,所以我们可以对request对象进行一系列的操作,包括request.变量名=变量值,这样的操作,我们可以在后续的视图函数中通过相同的方式即可获取到我们在中间件中设置的值。

    总结:

    • 中间件的process_request方法是在执行视图函数之前执行的。
    • 当配置多个中间件时,会按照MIDDLEWARE中的注册顺序,也就是列表的索引值,从前到后依次执行的。
    • 不同中间件之间传递的request都是同一个对象

    4、process_response

    process_response(self, request, response) ,多个中间件中的process_response方法是按照MIDDLEWARE中的注册顺序倒序执行的,也就是说第一个中间件的process_request方法首先执行,而它的process_response方法最后执行,最后一个中间件的process_request方法最后一个执行,它的process_response方法是最先执行。

    定义process_response方法时,必须给方法传入两个形参,request和response。request就是上述例子中一样的对象,response是视图函数返回的HttpResponse对象(也就是说这是Django后台处理完之后给出一个的一个具体的视图)。该方法的返回值(必须要有返回值)也必须是HttpResponse对象。如果不返回response而返回其他对象,则浏览器不会拿到Django后台给他的视图,而是我的中间件中返回的对象

    5、process_view

    process_view(self, request, view_func, view_args, view_kwargs)

    该方法有四个参数

    request是HttpRequest对象。

    view_func是Django即将使用的视图函数。 (它是实际的函数对象,而不是函数的名称作为字符串。)

    view_args是将传递给视图的位置参数的列表.

    view_kwargs是将传递给视图的关键字参数的字典。 view_args和view_kwargs都不包含第一个视图参数(request)。

    Django会在调用视图函数之前调用process_view方法。

    它应该返回None或一个HttpResponse对象。 如果返回None,Django将继续处理这个请求,执行任何其他中间件的process_view方法,然后在执行相应的视图。 如果它返回一个HttpResponse对象,那么将不会执行Django的视图函数,而是直接在中间件中掉头,倒叙执行一个个process_response方法,最后返回给浏览器

    process_view方法是在Django路由系统之后,视图系统之前执行的,执行顺序按照MIDDLEWARE中的注册顺序从前到后顺序执行

    6、process_exception

    process_exception(self, request, exception)

    该方法两个参数:

    一个HttpRequest对象

    一个exception是视图函数异常产生的Exception对象。

    这个方法只有在视图函数中出现异常了才执行,它返回的值可以是一个None也可以是一个HttpResponse对象。如果是HttpResponse对象,Django将调用模板和中间件中的process_response方法,并返回给浏览器,否则将默认处理异常。如果返回一个None,则交给下一个中间件的process_exception方法来处理异常。它的执行顺序也是按照中间件注册顺序的倒序执行

    7、process_template_response

    process_template_response(self, request, response)

    它的参数,一个HttpRequest对象,response是TemplateResponse对象(由视图函数或者中间件产生)。

    process_template_response是在视图函数执行完成后立即执行,但是它有一个前提条件,那就是视图函数返回的对象有一个render()方法(或者表明该对象是一个TemplateResponse对象或等价方法)

    8、中间件执行流程图

    img

    9、中间件版的登录验证

    中间件版的登录验证需要依靠session,所以数据库中要有django_session表。

    • view.py
    # 中间件版的登录认证
    def login_middle(request):
        if request.method == 'POST':
            username = request.POST.get('username')
            password = request.POST.get('password')
            login_obj_middle = models.user.objects.filter(username=username).first()
            if login_obj_middle:
                if login_obj_middle.password == int(password):
                    next = request.GET.get('next')
                    request.session['name'] = username
                    if next:
                        return redirect(next)
                    return redirect('/func_middle/')
        return render(request,'login_middle.html')
    
    
    def func_middle(request):
        return HttpResponse('你好我是首页~')
    
    
    def index_middle(request):
        return HttpResponse('这是index_middle页面,要经过中间件认证才能到达')
    
    • MyMiddleware.ware.py
    class auth_middleware(MiddlewareMixin):
        def process_request(self,request):
            path = request.path_info
            # 最最重要,如果不判断其路径是否是登录路径会造成重定向次数过多的情况
            if not path.startswith('/login_middle/'): 
                if not request.session.get('name'):
                    return redirect('/login_middle/?next={}'.format(path))
    
    
    • settings.py
    MIDDLEWARE = [
        'django.middleware.security.SecurityMiddleware',
        'django.contrib.sessions.middleware.SessionMiddleware',
        'django.middleware.common.CommonMiddleware',
        # 'django.MyMiddleware.csrf.CsrfViewMiddleware',
        'django.contrib.auth.middleware.AuthenticationMiddleware',
        'django.contrib.messages.middleware.MessageMiddleware',
        'django.middleware.clickjacking.XFrameOptionsMiddleware',
        # 'MyMiddleware.ware.Mymiddleware1', # 自定义中间件1
        # 'MyMiddleware.ware.Mymiddleware2', # 自定义中间件2
        'MyMiddleware.ware.auth_middleware'
    ]
    

    七、csrf跨站请求伪造

    1、什么是csrf,csrf攻击原理

    csrf:跨站请求伪造

    csrf攻击原理:攻击者盗用了你的身份,以你的名义发送恶意请求,然而对服务器来说这个请求完全是合法的

    要完成一次csrf攻击,受害者必须依次完成以下两个步骤

    • 登录受信任的网站A,并在本地生成Cookie
    • 在不退出A的情况下,访问B(不安全)

    2、csrf攻击防范

    """
    防止钓鱼网站的思路
        网站会给用户访问的form表单页面 偷偷塞一个随机字符串
            该随机字符串有以下特点
                  1.同一个浏览器每一次访问都不一样
                  2.不同浏览器绝对不会重复
        请求到来的时候 会先比对随机字符串是否一致  如果不一致  直接拒绝(403)
    """
    

    3、csrf在Django中的应用

    1、在form表单中使用
    <form action="" method="post">
        {% csrf_token %}
        <p>username:<input type="text" name="username"></p>
        <p>password:<input type="text" name="password"></p>
        <input type="submit">
    </form>
    
    • 这时再次打开网页检查源码,你会看到如下代码
    <input type="hidden" name="csrfmiddlewaretoken" value="vhTcZWUvUFPq6QaMwMMn7792WX1wJD7zPMjFHybaFbmygFeQUipvtijXeyItthj6">
    
    • 下一次提交给后端时后端就会校验name="csrfmiddlewaretoken"的值(这就是随机字符串,永远都不一样),如果一样就允许操作,不一样直接拒绝(403 Forbidden)

    • 在前端加上{% crsf_token %},后端settings里的MIDDLEWARE中的关于csrf的中间件以后就不用注释掉了

    MIDDLEWARE = [
        'django.middleware.security.SecurityMiddleware',
        'django.contrib.sessions.middleware.SessionMiddleware',
        'django.middleware.common.CommonMiddleware',
        'django.MyMiddleware.csrf.CsrfViewMiddleware',
      'django.contrib.auth.middleware.AuthenticationMiddleware',
        'django.contrib.messages.middleware.MessageMiddleware',
        'django.middleware.clickjacking.XFrameOptionsMiddleware',
        # 'MyMiddleware.ware.Mymiddleware1', # 自定义中间件1
        # 'MyMiddleware.ware.Mymiddleware2', # 自定义中间件2
        'MyMiddleware.ware.auth_middleware'
    ]
    
    2、在Ajax中的使用
    • 有两种方法,通过修改ajax中data

    方法一、先在form表单页面上写{% csrf_token%},利用标签查找,获取到该input键值消息

    data{'username':'xxxx','csrfmiddlewaretoken':$('[name=csrfmiddlewaretoken]').val()}
    

    方法二、直接书写’{{csrf_token}}’

    data{'username':'xxx','csrfmiddlewaretoken':'{{csrf_token}}'}
    
    • 还可以将获取随机键值对的方法,写到一个js文件中,然后导入这个文件即可

    新建一个js文件,存放以下代码

    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);
             }
         }
     });
    

    4、csrf装饰器

    1、csrf全局禁用

    直接注释掉settings中MIDDLEWARE的中间件 ‘django.middleware.csrf.CsrfViewMiddleware’,

    2、csrf局部禁用
    • 在FBV中使用,需要导入模块,直接加在FBV上(在页面不加{% csrf_token %}的情况下)
    from django.views.decorators.csrf import csrf_exempt,csrf_protect
    
    #(前提是全局使用,没有注释csrf)  让这个不用校验,可以局部使用
    #当你网站全局需要校验csrf的时候,有几个不需要校验该如何处理
    @csrf_exempt(全局校验就免除)
    def login(request):
        return HttpResponse('login')
    
    #(前提是全局禁用,注释csrf,不会进行校验)  设置就会进行校验,局部禁用
    #当你网站全局不校验csrf的时候,有几个需要校验又该如何处理
    @csrf_protect(全局不校验就保护)    
    def lll(request):
        return HttpResponse('lll')
    
    • 在CBV中使用,只能在dispatch方法或者类上面
    from django.views import View
    from django.views.decorators.csrf import csrf_exempt,csrf_protect
    from django.utils.decorators import method_decorator
    
    # 这两个装饰器在给CBV装饰的时候 有一定的区别
    如果是csrf_protect 那么有三种方式
    # 第一种方式
    # @method_decorator(csrf_protect,name='post')  # 有效的
    class MyView(View):
        # 第三种方式
        # @method_decorator(csrf_protect)
        def dispatch(self, request, *args, **kwargs):
            res = super().dispatch(request, *args, **kwargs)
            return res
    
        def get(self,request):
            return HttpResponse('get')
        # 第二种方式
        # @method_decorator(csrf_protect)  # 有效的
        def post(self,request):
            return HttpResponse('post')
    
    如果是csrf_exempt 只有两种(只能给dispatch装)   特例
    @method_decorator(csrf_exempt,name='dispatch')  # 第二种可以不校验的方式
    class MyView(View):
        # @method_decorator(csrf_exempt)  # 第一种可以不校验的方式
        def dispatch(self, request, *args, **kwargs):
            res = super().dispatch(request, *args, **kwargs)
            return res
    
        def get(self,request):
            return HttpResponse('get')
    
        def post(self,request):
            return HttpResponse('post')
    

    八、auth模块

    1、auth模块是什么

    Auth模块是Django自带的用户认证模块

    django在启动之后可以直接访问admin路由,但是需要登录,数据的参考就是auth_user表,并且还必须得是管理员用户才能进入

    创建超级用户(管理员)

    • python3 manage.py createsuperuser

    2、auth模块常用方法

    • 使用auth模块要用就用全套
    from django.contrib import auth
    
    1、auth.authenticate()
    auth.authenticate() # 去auth_user表中自动校验数据
    user_obj = auth.authenticate(request,username=username,password=password)
    user_obj.username
    user_obj.password
    ……
    """
    返回的是一个对象,auth.authenticate()类里有__str__方法
    1、自动查找auth_user标签
    2、自动给用户输入的密码加密后做比对
    用户名和密码是必须要传的
    数据不符合则返回None
    """
    
    2、auth.login()
    # 用户登录后保存用户的登录状态
    auth_login(request,user_obj)  # 类似于request.session[key] = user_obj
    """
    只要执行了该方法你就可以在整个项目的任意地方通过request.user拿到当前登陆的用户对象
    其原理就是:
    	自动取django_session表中查找对应的用户对象再封装到request.user中
    如果此对象不存在那么request.user返回的是AnonymousUser(匿名用户)
    """
    
    3、request.user.is_authenticated()
    # 判断用户是否登录
    request.user.is_authenticated()
    """
    返回True/False
    """
    
    4、logout()
    # 该函数接受一个HttpRequest对象,无返回值。
    def logout_view(request):
      auth.logout(request)
      # Redirect to a success page.
    """
    当调用该函数时,当前请求的session信息会全部清除。该用户即使没有登录,使用该函数也不会报错。
    """
    
    5、login_requierd()
    # 一个装饰器工具,用来快捷的给某个视图添加登录校验。
    from django.contrib.auth.decorators import login_required
          
    @login_required
    def my_view(request):
      ...
    """
    若用户没有登录,则会跳转到django默认的 登录URL '/accounts/login/ ' 并传递当前访问url的绝对路径 (登陆成功后,会重定向到该路径)。
    如果需要自定义登录的URL,则需要在settings.py文件中通过LOGIN_URL进行修改。
    """
    @login_required(login_url='/login/') # 局部配置【使用不当会造成重定向次数过多】
    LOGIN_URL = '/login/'  # 这里配置成你项目登录页面的路由(全局配置)
    优先级  局部大于全局
    局部和全局使用视情况而定
    
    path = request.get_full_path()
    if not path.endswith('/app02/login/'):
        next = request.GET.get('next')
        return redirect(next)
    return HttpResponse('haha')
    
    @login_required
    def home(request):
        return HttpResponse('OK')
    
    @login_required
    def index(request):
        return HttpResponse('INDEX')
    
    5、create_user()
    # auth 提供的一个创建新普通用户的方法,需要提供必要参数(username、password)等。
    from django.contrib.auth.models import User
    user = User.objects.create_user(username='用户名',password='密码',email='邮箱',...
    6、create_superuser()
    # auth 提供的一个创建新的超级用户的方法,需要提供必要参数(username、password)等。
    from django.contrib.auth.models import User
    user = User.objects.create_superuser(username='用户名',password='密码',email='邮箱',...
    7、check_password(password)
    # auth 提供的一个检查密码是否正确的方法,需要提供当前请求用户的密码。
    ok = user.check_password("老密码"'新密码')
    """
    密码正确返回True,否则返回False。
    """
    
    8、set_password(password)
    # auth 提供的一个修改密码的方法,接收 要设置的新密码 作为参数。
    """
    注意:设置完一定要调用用户对象的save方法!!!
    """
    user.set_password(password='')
    user.save()
    
    10、User对象的属性
    """
    User对象属性:username, password
    is_staff : 用户是否拥有网站的管理权限.
    is_active : 是否允许用户登录, 设置为 False,可以在不删除用户的前提下禁止用户登录。
    """
    

    3、auth模块表的扩展

    我们可以通过继承内置的 AbstractUser 类,来定义一个自己的Model类。

    这样既能根据项目需求灵活的设计用户表,又能使用Django强大的认证系统了。

    from django.contrib.auth.models import AbstractUser
    class UserInfo(AbstractUser):
        """
        用户信息表
        """
        nid = models.AutoField(primary_key=True)
        phone = models.CharField(max_length=11, null=True, unique=True)
        
        def __str__(self):
            return self.username
        """
        如果继承了AbstractUser,在执行数据库迁移命令时
        auth_user表不会再被创建出来,被创建出的表名则是我们自己定义的类名
        而Userinfo表中会出现auth_user表中所有的字段且还有Userinfo自己扩展的字段
        前提:
        	1、在继承之前数据库迁移命令没有被执行(auth_user表没有被创建出来)
        	2、继承的类AbstractUser里面的字段名不要被覆盖
        """
    

    注意:

    按上面的方式扩展了内置的auth_user表之后,一定要在settings.py中告诉Django,我现在使用我新定义的UserInfo表来做用户认证。写法如下:

    # 引用Django自带的User表,继承使用时需要设置
    AUTH_USER_MODEL = "app名.UserInfo"
    

    一旦我们指定了新的认证系统所使用的表,我们就需要重新在数据库中创建该表,而不能继续使用原来默认的auth_user表了。

    展开全文
    prigilm 2021-11-03 18:21:01
  • 3星
    47KB huangzhang_123 2017-05-25 11:37:50
  • new projet 选django(前提是你已经下载了django了) 1.解释器的选择 2.自动创建app(自动帮你注册到配置文件中) 3.会自动帮你新建一个templates文件夹(自动帮你注册到配置文件中) 创建应用 python3 manage.py ...

    上周内容回顾
    HTTP协议
    四大特性:
    1 基于TCP/IP作用于应用层的协议
    2 基于请求响应
    3 无状态
    4 无连接
    请求数据格式
    请求首行
    请求头(一大堆k,v键值对)
    请求体(post请求携带的数据)
    响应数据格式
    响应首行
    响应头(一大堆k,v键值对)
    响应体(用户想要的数据)
    响应状态码
    1XX 服务器已经接收到你提交的数据正在处理,你可以继续提交
    2XX 请求成功 返回相应的数据
    3XX 重定向
    4XX 请求错误(404请求资源不存在)
    5XX 服务端错误

    Django
    安装django之前你需要注意的几个事项
    1.版本问题 建议使用1.11.11左右的版本(******)
    2.计算机名称不能有中文
    3.项目名不要用中文
    4.一个pycharm窗口只有一个项目
    安装
    pip3 install django==1.11.11
    命令行创建
    django-admin startproject 项目名
    命令行创建应用
    python3 manage.py startapp 应用名
    命令行启动django项目
    python3 manage.py runserver
    ps:命令行创建django项目,不会自动新建templates文件夹
    需要你手动新建,并且你应该去配置文件中将该文件夹路径添加就去
    pycharm创建django项目
    new projet 选django(前提是你已经下载了django了)
    1.解释器的选择
    2.自动创建app(自动帮你注册到配置文件中)
    3.会自动帮你新建一个templates文件夹(自动帮你注册到配置文件中)

    	创建应用
    		python3 manage.py startapp 应用名
    		Tools里面的run manage.py task
    		注意:新建的app一定要在配置文件中先注册(******)
    		
    	启动项目
    		python3 manage.py runserver
    		绿色小箭头启动(可以修改端口号)
    		注意:不要一次起多个django项目(同一个端口下)(******)
    		
    django连接MySQL(******)
    	1.修改配置文件中DATABASES变量指代的配置
    		将默认的数据库引擎由默认的sqlite改为mysql
    		NAME	数据库名
    		USER
    		PASSWORD
    		HOST
    		PORT
    	2.去__init__.py(可以是项目下的也可以是应用下的)文件中
    	import pymysql
    	pymysql.install_as_MySQLdb()  告诉django用pymysql模块去操作数据库
    

    django小白必会三板斧
    HttpReponse 返回字符串
    render 渲染页面
    redirect 重定向
    ps:django返回给前端的数据都是HttpResponse对象

    ORM模型层
    对象关系映射
    class User(models.Model):
    # 主键字段可以不写,django会自动帮你创建一个字段名为id的主键字段
    uid = models.AutoField(primary_key=True)
    # name(varchar(32))
    name = models.CharField(max_length=32) django默认没有类对应char类型

    数据库迁移命令(******)
    python3 manage.py makemigrations 将数据库更改记录添加到小本本上(对应应用下migrations文件夹)
    python3 manage.py migrate 将更改同步到数据库(真正的操作数据库)
    ps:上述命令记得滚瓜烂熟之后可以使用pycharm提供的简便的命令行操作

    模型表字段的增删改查

    表没有的数据情况下,直接执行数据库迁移命令即可
    有数据的情况下,新增的字段需要有个默认值(default=‘默认值’,null=True),然后执行数据库迁移命令
    删(一般情况下是不会删除的)

    执行数据库迁移命令
    强调:只要你修改了与数据库表相关的记录,你就必须得从头开始执行数据库迁移命令

    模型表数据的增删改查

    res = models.User.objects.all() 获取user表中所有的数据,返回的是一个queryset对象(你就把它当成是一个列表里面放的是一个个的数据对象)
    print(res.query) 查看当前queryset对象内部对应的sql语句
    注意:只有queryset对象才可以点query方法

    	res = models.User.objects.filter(name='jason')  去数据库将name字段对应的值为jason所有的数据都出来
    	filter返回的结果是一个queryset对象
    	ps:queryset对象支持索引取值,但是它不支持负数索引(******)
    	
    	res = models.User.objects.get(name='jason')
    	返回的结果就是数据对象本身,这个方法当条件不存在的情况直接报错
    
    增
    	user_obj = models.User.objects.create(name='jason')
    	create方法有一个返回值,就是当前新增的数据对象本身
    	
    	user_obj = models.USER(name='jason')
    	user_obj.save()
    	
    改(是基于已经有的数据的基础之上继续修改)
    	user_obj = models.User.objects.filter(name='jason').first()
    	user_obj.name = 'egon'
    	user_obj.save()
    		
    	
    	user_list = models.User.objects.filter(name='jason').update(name='xxx')
    	调用queryset封装的方法,该方法是一个批量操作,会将queryset内所有的数据对象全部修改
    	
    删
    	models.User.objects.filter(name='jason').delete()
    

    今日内容
    路由层
    无名分组
    有名分组
    反向解析
    路由分发
    名称空间

    伪静态网页
    
    虚拟环境
    
    视图层
    	JsonReponse
    	FBV与CBV
    	文件上传
    	
    	
    	
    	
    	
    urlpatterns = [
    			url(r'^admin/', admin.site.urls),
    			url(r'^$',views.home),
    			url(r'^test/$',views.test),
    			url(r'^testadd/$',views.testadd),
    			url(r'',views.error)
    		]
    注意:第一个参数是正则表达式,匹配规则按照从上往下一次匹配,匹配到一个之后立即匹配,直接执行对应的视图函数
    
    网站首页路由
    url(r'^$',views.home)
    网站不存在页面
    url(r'',views.error)
    	
    
    无名分组(将加括号的正则表达式匹配到的内容当做位置参数自动传递给对应的视图函数)
    	url(r'^test/(\d+)/',views.test),  # 匹配一个或多个数字
    	
    	def test(request,xxx):
    		print(xxx)
    		return HttpResponse('test')
    
    有名分组(将加括号的正则表达式匹配到的内容当做关键字参数自动传递给对应的视图函数)
    	url(r'^test/(?P<year>\d+)/',views.test),  # 匹配一个或多个数字
    	
    	def test(request,year):
    		print(year)
    		return HttpResponse('test')
    
    	注意:无名分组和有名分组不能混着用!!!
    		url(r'^test/(\d+)/(?P<year>\d+)/',views.test)
    
    
    但是支持用一类型多个形式匹配
    无名分组多个
    	url(r'^test/(\d+)/(\d+)/',views.test),
    有名分组多个
    	url(r'^test/(?P<year>\d+)/(?P<xxx>\d+)/',views.test),
    
    
    
    反向解析(根据名字动态获取到对应路径)
    	from django.shortcuts import reverse
    	
    	url(r'^index6668888/$',views.index,name='index')
    	# 可以给每一个路由与视图函数对应关系起一个名字
    	# 这个名字能够唯一标识出对应的路径
    	# 注意这个名字不能重复是唯一的
    	
    前端使用
    	{% url 'index' %}
    	{% url '你给路由与视图函数对应关系起的别名' %}
    
    后端使用
    	reverse('index')
    	reverse('你给路由与视图函数对应关系起的别名')
    
    无名分组反向解析
    	url(r'^test/(\d+)/',views.test,name='list')
    	
    	后端使用
    		print(reverse('list',args=(10,)))
    	前端使用
    		{% url 'list' 10 %}
    	
    	user_list = models.User.objects.all()
    	
    	
    	url(r'^edit/(\d+)/',views.edit,name='edit')
    	前端模板语法
    		{%for user_obj in user_list%}
    			<a href='edit/{{ user_obj.pk }}/'></a>
    		{% endfor %}
    	
    	视图函数
    	from django.shortcuts import reverse
    	def edit(request,edit_id):
    		url = reverse('edit',args=(edit_id,))
    		
    	模板
    		{% url 'edit' edit_id %}
    

    有名分组反向解析

    后端使用
    			# 后端有名分组和无名分组都可以用这种形式
    			print(reverse('list',args=(10,)))
    			# 下面这个了解即可
    			print(reverse('list',kwargs={'year':10}))
    		前端使用
    			# 前端有名分组和无名分组都可以用这种形式
    			{% url 'list' 10 %}
    			# 下面这个了解即可
    			{% url 'list' year=10 %}
    	总结:针对有名分组与无名分组的反向解析统一采用一种格式即可
    		后端
    		reverse('list',args=(10,))  # 这里的数字通常都是数据的主键值
    		前端
    		{% url 'list' 10 %}
    反向解析的本质:就是获取到一个能够访问名字所对应的视图函数
    

    路由分发
    django每一个app下面都可以有自己的urls.py路由层,templates文件夹,static文件夹
    项目名下urls.py(总路由)不再做路由与视图函数的匹配关系而是做路由的分发
    from django.conf.urls import include

    # 路由分发  注意路由分发总路由千万不要$结尾
    url(r'^app01/',include(app01_urls)),
    url(r'^app02/',include(app02_urls))
    
    # 在应用下新建urls.py文件,在该文件内写路由与视图函数的对应关系即可
    from django.conf.urls import url
    from app01 import views
    urlpatterns = [
    	url(r'^index/',views.index)
    ]
    
    
    
    名称空间(了解)
    	url(r'^app01/',include(app01_urls,namespace='app01')),
    	url(r'^app02/',include(app02_urls,namespace='app02'))
    app01.urls.py
    	from django.conf.urls import url
    	from app01 import views
    	urlpatterns = [
    		url(r'^index/',views.index,name='index')
    	]
    
    app02.urls.py
    	from django.conf.urls import url
    	from app02 import views
    	urlpatterns = [
    		url(r'^index/',views.index,name='index')
    	]
    
    app01.views.py
    reverse('app01:index')
    
    app02.views.py
    reverse('app02:index')
    
    
    
    伪静态网页
    	搜索优化seo
    	url(r'^index.html',views.index,name='app01_index')
    
    
    
    
    虚拟环境
    	不同的项目配置不同的python解释器
    
    django1.0与django2.0之间的区别
    	django2.0里面的path第一个参数不支持正则,你写什么就匹配,100%精准匹配
    	
    	django2.0里面的re_path对应着django1.0里面的url
    	
    虽然django2.0里面的path不支持正则表达式,但是它提供五个默认的转换器
    
    	str,匹配除了路径分隔符(/)之外的非空字符串,这是默认的形式
    	int,匹配正整数,包含0。
    	slug,匹配字母、数字以及横杠、下划线组成的字符串。
    	uuid,匹配格式化的uuid,如 075194d3-6885-417e-a8a8-6c931e272f00。
    	path,匹配任何非空字符串,包含了路径分隔符(/)(不能用?)
    
    自定义转换器
    	1.正则表达式
    	2.类
    	3.注册
    
    # 自定义转换器
    class FourDigitYearConverter:
    	regex = '[0-9]{4}'
    	def to_python(self, value):
    		return int(value)
    	def to_url(self, value):
    		return '%04d' % value  # 占四位,不够用0填满,超了则就按超了的位数来!
    register_converter(FourDigitYearConverter, 'yyyy')
    PS:路由匹配到的数据默认都是字符串形式
    	
    
    
    
    FBV与CBV
    FBV:基于函数的视图
    CBV:基于类的视图
    
    CBV:
    	url(r'^mycls/',views.MyCls.as_view())
    
    	class MyCls(View):
    		def get(self,request):
    			return render(request,'index.html')
    		def post(self,request):
    			return HttpResponse('post')
    
    无论是FBV还是CBV路由层都是路由对应视图函数内存地址
    urlpatterns = [
    	# url(r'^mycls/',views.view)
    	url(r'^mycls/',views.MyCls.as_view())
    ]
    
    class MyCls(View):
    	def get(self,request):
    		return render(request,'index.html')
    	def post(self,request):
    		return HttpResponse('post')
    	
    
    小白必会三板斧
    	HttpResponse
    	render
    	redirect
    
    JsonResponse
    from django.http import JsonResponse
    def index(request):
    	# res = {'name':'Jason大帅比','password':18}
    	# return HttpResponse(json.dumps(res))
    	return JsonResponse({'name':'Jason大帅比','password':'1888888'},json_dumps_params={'ensure_ascii':False})
    
    
    
    
    
    print('path:',request.path)
    print('full_path:',request.get_full_path())
    
    path: /upload_file/
    full_path: /upload_file/?name=jason
    
    
    
    简单的文件上传
    前端需要注意的点:
    	1.method需要指定成post
    	2.enctype需要改为formdata格式
    
    后端暂时需要注意的是
    	1.配置文件中注释掉csrfmiddleware中间件
    	2.通过request.FILES获取用户上传的post文件数据
    	
    file_obj = request.FILES.get('my_file')
        print(file_obj.name)
        with open(file_obj.name,'wb') as f:
            for line in file_obj.chunks():
                f.write(line)
    

    作业:
    1.利用反向解析渲染图书管理系统

    思考题
    import importlib
    importlib.import_module(‘app01.urls’)
    # from app01 import urls

    展开全文
    weixin_43183295 2019-06-10 20:12:20
  • 一、django层面: 1、django migrations原理; 2、django信号量; 3、Django请求到响应的完整过程; 4、独立使用django model; 二、vue层面: 1、vue选型分析; 2、api后端接口数据填充到vue组件模板; 3...

    一、django层面:

    1、django migrations原理;

    2、django信号量;

    3、Django请求到响应的完整过程;

    4、独立使用django model;

     

    二、vue层面:

    1、vue选型分析;

    2、api后端接口数据填充到vue组件模板;

    3、vue代码结构分析;

     

    三、结构安排:

    设计数据库、导入原始数据;

    restful api基础与vue项目结构介绍;

    商品列表页功能

    商品类别功能

    手机注册与用户登录

    商品详情页与收藏

    个人中心

    订单与支付

    首页相关数量、访问缓存

    第三方登录

    sentry监控

     

    四、技术储备

    1、django基础;

    2、python、mysql、vue

     

     

     

     

     

    展开全文
    qq471011042 2019-04-16 10:42:46
  • 150KB weixin_38739942 2020-09-20 04:53:49
  • 96KB weixin_38679449 2020-09-20 04:08:54
  • 1.26MB weixin_42102272 2021-05-30 07:56:22
  • 丰富django admin form 上下文管理器 1.概念:上下文处理器是可以返回一些数据,在全局模板中都可以使用。比如登录后的用户信息,在很多页面中都需要使用,那么我们可以放在上下文处理器中,就没有必要在每个视图...

    上下文管理器
    多对多关联
    分页
    丰富django admin
    form

    • 上下文管理器

    1.概念:上下文处理器是可以返回一些数据,在全局模板中都可以使用。比如登录后的用户信息,在很多页面中都需要使用,那么我们可以放在上下文处理器中,就没有必要在每个视图函数中都返回这个对象。

    2.为何要使用?
    如果我们不使用上下文处理器的话,那么我们需要在每一个视图函数中都去获取一下session中的user_id,这就是一件很不爽的事情了,而如果我们定义了上下文处理器,那么我们就不需要每一个视图函数中都去获取session中user_id的值了,只需要在上下文处理器中去获取就是了。

    3.app目录下新建一个context_processors.py的文件

    from . import models
    
    def category_process(request):
        categories = models.Category.objects.filter(is_delete=False)
        return  {'nav':categories}
    
    def site_process(request):
        site_name = '王庆柱的博客'
        desc = "今天很困,一会要抽烟"
        return locals() #把当前函数里面的局部变量都返回
    

    4.sitting.py进行配置

    TEMPLATES = [
        {
            'BACKEND': 'django.template.backends.django.DjangoTemplates',
            'DIRS': [os.path.join(BASE_DIR, 'templates'),
                        os.path.join(BASE_DIR, 'html')
                     ]
            ,
            'APP_DIRS': True,
            'OPTIONS': {
                'context_processors': [
                    'django.template.context_processors.debug',
                    'django.template.context_processors.request',
                    'django.contrib.auth.context_processors.auth',
                    'django.contrib.messages.context_processors.messages',
                    'user.process_content.category_process',
                    #上下文处理器
                    'user.process_content.site_process'
    
                ],
            },
        },
    ]
    

    模板继承

    建立一个base.html

    模板的继承,主要的作用就是实现模板内html代码的重复利用,方便维护和修改,比如一个网站每个网页的页头和页脚信息固定,这样就不需要在每个html页面加入页头和页尾代码,只需要在一个html文件中创建一个模板,其他html页面直接引用即可

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    {% block test1 %}
        “此处是要展示的页头信息”
    {% endblock %}
    {% block content %}
        "此处是要替换的内容"
    {% endblock %}
    {% block test2 %}
        “此处是要展示的页尾信息”
    {% endblock %}
    </body>
    </html>
    

    其中的两个block就是等待被继承的信息。

    此时如果要文件home.html来继承,在文件里面直接展示出页头和页尾信息,这样就只需要在home中引用base.html

    {% extends ‘base.html’ %}

    然后再指定需要替换的模板,比如我是要在home中,保持home内容完全展示的基础上,再加上页头和页尾信息。

    这样,我就只需要替换{% block content %}
    “此处是要替换的内容”
    {% endblock %} 这个block中的内容,保留页头和页尾的block。具体的实现如下

    {% extends 'base.html' %}
    {% load my_tag %}
    
    {% block content %}
        <article>
            <aside>
                <div class="l_box" id="stickMe">
                    <div class="about_me">
                        <h2>关于我</h2>
                        <ul>
                            <i><img src="/static/images/4.jpg"></i>
                            <p>{{ desc }}</p>
                        </ul>
                    </div>
                    <div class="wdxc">
                        <h2>我的相册</h2>
                        <ul>
                            <li><a href="/"><img src="/static/images/7.jpg"></a></li>
                           
                        </ul>
                    </div>
                    <div class="search">
                        <form action="/e/search/index.php" method="post" name="searchform" id="searchform">
                            <input name="keyboard" id="keyboard" class="input_text" value="请输入关键字词"
                                   style="color: rgb(153, 153, 153);"
                                   onfocus="if(value=='请输入关键字词'){this.style.color='#000';value=''}"
                                   onblur="if(value==''){this.style.color='#999';value='请输入关键字词'}" type="text">
                            <input name="show" value="title" type="hidden">
                          class="input_submit" value="搜索" type="submit">
                        </form>
                    </div>
                    <div class="fenlei">
                        <h2>文章分类</h2>
                        <ul>
                            <li><a href="/">学无止境(33</a></li>
                           
                        </ul>
                    </div>
                    <div class="tuijian">
                        <h2>站长推荐</h2>
                        <ul>
                            <li><a href="/">你是什么人便会遇上什么人</a></li>
                        
                        </ul>
                    </div>
                    <div class="links">
                        <h2>友情链接</h2>
                        <ul>
                            <a href="http://www.yangqq.com">杨青个人博客</a> <a href="http://www.yangqq.com">杨青博客</a>
                        </ul>
                    </div>
                    <div class="guanzhu">
                        <h2>关注我 么么哒</h2>
                        <ul>
                            <img src="/static/images/wx.jpg">
                        </ul>
                    </div>
                </div>
            </aside>
            <div class="r_box">
                {% for aricle in articles %}
    
                    <li><i>
    {#                    <a href="/detail?id={{ aricle.id }}">#}
                        <a href="{% url 'xiangqing' %}?id={{ aricle.id }}">
    
                            <img src="/static/{{ aricle.img }}"></a></i>
    
                        <h3><a href="{% url 'xiangqing' %}?id={{ aricle.id }}">{{ aricle.title }}</a></h3>
    {#                        <p>{{ aricle.desc }}</p>#}
                        <p>{{ aricle.desc | abc:5 }}</p>
    {#                    <p>{% abc2 ricle.desc 20  %}</p>#}
                    </li>
    
                {% endfor %}
    
                {% if articles.has_other_pages %}
    
                <div class="pagelist">
                    {% if articles.has_previous %}
                    <a  href="/index?page={{ articles.previous_page_number }}&limit=10" ><b>上一页</b></a>&nbsp;&nbsp;
                        {% endif %}
    
    
                    {% for page_num in articles.paginator.page_range %}
    
                    <a href="/index?page={{ page_num }}&limit=10" >{{ page_num }}</a>&nbsp;&nbsp;
    
                    {% endfor %}
    
                    {% if articles.has_next %}
                    <a href="/index?page={{ articles.next_page_number }}&limit=10">下一页</a>
    
                        {% endif %}
                </div>
            {% endif %}
    
            </div>
        </article>
    
    {% endblock %}
    

    分页后端实现
    paginator

    from django.core.paginator import Paginator
    from . import const
    
    def index(request):
        category_id = request.GET.get('category_id',1) #?category_id=xx
        page = request.GET.get('page',1)
        limit = request.GET.get('limit',const.page_size)
        article = Article.objects.filter(is_delete=False,category_id=category_id)
        page_obj = Paginator(article,limit)
        page_data = page_obj.page(page)
        data = {'articles':page_data}
        return render(request,'index.html',data)
    
    • 建立一个const.py,配置默认分页数量
    page_size = 10 #默认分页数量
    

    分页前端实现

    
                {% if articles.has_other_pages %}
    
                <div class="pagelist">
                    {% if articles.has_previous %}
                    <a  href="/index?page={{ articles.previous_page_number }}&limit=10" ><b>上一页</b></a>&nbsp;&nbsp;
                        {% endif %}
    
    
                    {% for page_num in articles.paginator.page_range %}
    
                    <a href="/index?page={{ page_num }}&limit=10" >{{ page_num }}</a>&nbsp;&nbsp;
    
                    {% endfor %}
    
                    {% if articles.has_next %}
                    <a href="/index?page={{ articles.next_page_number }}&limit=10">下一页</a>
    
                        {% endif %}
    
    • 分页常用
    from django.core.paginator import Paginator
    
    page_obj = Paginator(Article.objects.all(),2)
    print(list(page_obj.page(1)))
    
    print(page_obj.page(1)) #取某一页的数据
    print(page_obj.count) #总共多少条
    print(page_obj.num_pages) #总共分了多少页
    
    print(page_obj.page_range) #分页的范围
    
    cur_page = page_obj.page(1)
    
    print(cur_page.has_previous()) #判断是否有上一页
    # print(cur_page.previous_page_number())
    print(cur_page.has_next())#判断是否有下一页
    

    丰富django admin
    优化自带的

    • pip install simpleui,安装此模板
    • sitting.py里面增加此模板
    INSTALLED_APPS = [
        'simpleui',
    
    • admin.py丰富功能
    from django.contrib import admin
    
    # Register your models here.
    from . import models
    
    class ArticleAdmin(admin.ModelAdmin):
        list_display = ['title', 'category', 'create_time', 'update_time'] #显示哪些字段
        search_fields = ['title'] #哪写字段可以搜索,不要写外键的字段
        list_filter = ['category','is_delete']
        list_per_page = 10 #每页显示多少条
    
    
    class CategoryAdmin(admin.ModelAdmin):
        list_display = ['name', 'create_time', 'update_time'] #显示哪些字段
        search_fields = ['name'] #哪写字段可以搜索,不要写外键的字段
        list_filter = ['is_delete']
        list_per_page = 10 #每页显示多少条
    
    
    
    admin.site.register(models.Category,CategoryAdmin)
    admin.site.register(models.Article,ArticleAdmin)
    

    解决跨域问题

    pip install django-cors-headers
    

    前端自定义标签
    templatetags包-my_tag.py

    from django import template
    
    register = template.Library()
    
    @register.filter #最多就2个参数
    def abc(s,length=10):
        if len(s)>length:
            s = s[:11]+'....'
        return s
    
    @register.simple_tag
    def abc2(s,length=10):
        if len(s)>length:
            s = s[:11]+'....'
        return s
    
    • index.html
    {% load my_tag %}
    
    
    展开全文
    weixin_42037775 2020-05-17 22:09:28
  • qq_42470018 2019-03-31 23:08:27
  • 3.17MB weixin_27219587 2021-06-10 14:13:51
  • u011331731 2020-07-05 17:25:12
  • alex3714 2018-08-22 16:16:13

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 10,815
精华内容 4,326
关键字:

django进阶

友情链接: dumptest.rar