美文网首页
07-Django高级使用

07-Django高级使用

作者: 王梓懿_1fbc | 来源:发表于2018-10-21 12:33 被阅读15次

    一、静态文件

    • 简述
    CSS、JS、JSON、图片、字体文件...
    
    
    • 配置settings.py
    STATIC_URL='/static/'
    STATICFILES_DIRS = [
        os.path.join(BASE_DIR, 'static'),
    ]
    
    
    • 示例
    {% load static %}
    
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>饿了吗 | 首页</title>
        <link rel="stylesheet" type="text/css" href="{% static 'elema/css/style.css' %}"/>
        <script type="text/javascript" src="{% static 'elema/js/jquery-3.1.1.min.js' %}"></script>
        <script type="text/javascript" src="{% static 'elema/js/index.js' %}"></script>
    </head>
    
    <body>
        <h1>饿了吗?</h1>
        <img src="{% static 'elema/img/1.jpeg' %}">
    </body>
    
    </html>
    
    

    在项目文件中创建static,并创建对应的应用目录,在应用目录里面添加例如js、img、css等目录

    二、中间件

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

    本质: 就是一个python类
    应用场景: 统计、黑名单、白名单、反爬...

    • 方法
    - __init__
        不需要传参,服务器响应第一个请求的时,会自动调用,用于确定是否启用中间件
    - process_request(self,request)
        在视图执行前调用(即分配url匹配视图之前),每个请求都会调用,返回None或HttpResponse对象
    - process_view(self,request,view_func,view_args,view_kwargs)
        调用视图之前执行,每个请求都会调用,返回None或HttpResponse对象
    - process_templae_response(self,request,response)
        在视图刚好执行完后调用,每个请求都会调用,返回None或HttpResponse对象
    - process_response(self,request,response)
        所有响应返回浏览器之前调用,每个请求都会调用,返回None或HttpResponse对象
    - process_exception(self,request,exception)
        当视图出现异常时调用,返回HttpResponse对象
    
    备注: 为什么会返回HttpRespons对象?因为在请求进来后如果有问题,就可以不做后续处理,直接给客户端响应。
    
    

    settings.py中的MIDDLEWARE = [...]就中间件。

    • 方法执行

    • 自定义中间件并使用

    在工程目录下middleware目录下创建应用目录
    - 在middleware/elema中创建一个elemamiddleware.py
    from django.utils.deprecation import MiddlewareMixin
    class MyMiddle(MiddlewareMixin):
        # 在视图执行前调用
        def process_request(self,reqeust):
            print('get请求,参数name: ', reqeust.GET.get('name'))
    
    - 配置settings.py文件(即在MIDDLEWARE中添加上述文件的位置)
        'middleware.elema.elemamiddleware.MyMiddle'
    
    - 浏览器
        http://127.0.0.1:8000/?name=zyz
    
    - 效果  
        在终端中可以看到`get请求,参数name:  zyz`
    
    
    • 中间件(黑名单拦截)
    # 拦截器,拦截他黑名单中的IP
    class MyMiddle(MiddlewareMixin):
        def process_request(self, request):
          if request.META['REMOTE_ADDR'] in getattr(settings, 'BLOCKED_IPS', []):
            return HttpResponse('<h1>Forbidden</h1>')
    
    # settings.py中
    BLOCKED_IPS = [  # IP黑名单
        '192.168.0.100'
    ]
    
    
    • 中间件(未登陆处理)
    class MyMiddle(MiddlewareMixin):
        def process_request(self, request):
            # request.META['REMOTE_ADDR']  请求的IP地址
            if request.path !='/meituan/login/': # 检测如果不是登录的话
                if "username" in request.COOKIES:   # 已经登录不做任何处理
                    pass
                else:   # 未登录,重定向到登录页面
                    return HttpResponseRedirect('/meituan/login/')
    
    

    三、上传图片

    • 注意
    - 文件上传时,文件数据存储在request.FILES属性中
    - form表单要上传文件需要加 enctype="multipart/form-data"
    - 上传文件必须是post请求
    
    
    • 存储路径
    - 在static目录下创建upfile目录用于存储接受上传的文件
    - 配置settings.py文件
        MDEIA_ROOT = os.path.join(BASE_DIR,'static/upfile')
    
    
    • 示例
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>文件上传</title>
    </head>
    <body>
        <form action="{% url 'elema:savefile' %}" method="post" enctype="multipart/form-data">
            {% csrf_token %}
            <input type="file" value="上传文件" name="file">
            <input type="submit" value="上传">
        </form>
    </body>
    </html>
    
    
    # 文件上传
    def upfile(request):
        return render(request, 'elema/upfile.html')
    
    # 文件保存
    import os
    from django.conf import settings    # 导入settings.py
    def savefile(request):
        # 判断是否为POST
        if request.method == 'POST':
            # 获取文件内容
            file = request.FILES['file']
            # 文件保存路径
            filepath = os.path.join(settings.MDEIA_ROOT,file.name)
            # 文件写入
            with open(filepath,'wb') as fp:
                for info in file.chunks():
                    fp.write(info)
            return HttpResponse('文件上传成功')
        else:
            return HttpResponse('文件上传失败')
    
    

    四、分页

    • Paginator创建对象
    格式: Paginator(列表,每页个数)
    返回值: 分页对象
    
    
    • Paginator属性
    count: 对象总数
    num_pages: 页面总数
    page_range: 页码列表(页码从1开始)
    
    
    • Paginator方法
    page(num): 获得一个Page对象,如果提供的页面不存在会抛出'InvalidPage'异常
    
    
    • Paginator异常
    InvalidPage: 当向page()传递是一个无效页码时抛出
    PageNotAnInteger: 当向page()传递的不是一个整数时抛出
    EmptyPage: 当向page()传递一个有效值,但该页面没有数据时抛出
    
    
    • Page创建对象
    Paginator对象的page()方法返回得到Page对象(不需要手动创建)
    
    
    • Page属性
    object_list: 当前页上所有的数据(对象)列表
    number: 当前页的页码值
    paginator: 当前page对象关联的paginator对象
    
    
    • Page方法
    has_next(): 判断是否有下一页,如果有返回True
    has_previous(): 判断是否有上一页,如果有返回True
    has_other_pages(): 判断是否有上一页或下一页,如果有返回True
    next_page_number(): 返回下一页的页码,如果下一页不存在抛出InvalidPage异常
    previous_page_number(): 返回上一页的页码,如果上一页不存在抛出InvalidPage异常
    len(): 返回当前页的数据(对象)个数
    
    
    • Paginator对象与Page对象关系

    • 示例

    # urls.py文件
    url(r'^goodslist/(\d+)/$',views.goodslist, name='goodslist'), # 商品列表 
    
    
    # views.py文件
    # 商品列表
    from .models import Goods
    from django.core.paginator import Paginator
    def goodslist(request,page):
        # 所有商品数据
        alllist = Goods.objects.all()
    
        # 10条数据为一页,划分总页数
        # 分页对象
        paginator = Paginator(list(alllist),10)
    
        # 根据传入的页码得到Page对象
        pageobj = paginator.page(page)
    
        # return HttpResponse('page:'+page)
        return render(request,'elema/goodslist.html',{'pageobj':pageobj})
    
    
    # models.py文件
    # 商品 模型类
    class Goods(models.Model):
        # 商品名称
        name = models.CharField(max_length=20)
        # 商品图片
        icon = models.CharField(max_length=255)
        # 商品价格
        price = models.IntegerField()
        # 商品描述
        detail = models.CharField(max_length=255)
    
        class Meta:
            db_table = 'goods' 
    
    
    # 存储过程: 创建商品数据(产生批量数据)
    # 第一步: 创建上述Goods模型类 【注意表名是goods】
    # 第二步: 生成迁移文件,并执行迁移
    # 第三步: 进入到对应的数据库中,检查表单结构是否一致
    mysql> desc goods;
    +--------+--------------+------+-----+---------+----------------+
    | Field  | Type         | Null | Key | Default | Extra          |
    +--------+--------------+------+-----+---------+----------------+
    | id     | int(11)      | NO   | PRI | NULL    | auto_increment |
    | name   | varchar(20)  | NO   |     | NULL    |                |
    | icon   | varchar(255) | NO   |     | NULL    |                |
    | price  | int(11)      | NO   |     | NULL    |                |
    | detail | varchar(255) | NO   |     | NULL    |                |
    +--------+--------------+------+-----+---------+----------------+
    # 第四步: 将图片 'cymbal.png'等,放置在'/static/img'目录
    
    # 第五步: 创建 存储过程 添加到数据库中(复制到mysql终端中)
    # insert into elema_goods(name,icon,price,detail) value(_name,_icon,_price,_detail)
    delimiter //
    create procedure add_goods(num int(4))
    begin
        # 定义变量
        declare _i,_price,_temp int(4) default 0;
        declare _name,_icon,_detail varchar(255) default '';
        declare BASE_PATH varchar(255) default '/static/img/';
    
        # 循环
        while _i<num do
            # 设置变量
            set _temp = round(rand()*10000+1000);
            set _name = concat(_temp,'-商品名称');
            set _temp = round(rand()*5+1);
            case _temp
            when 1 then
                set _icon = concat(BASE_PATH,'1.jpg');
            when 2 then
                set _icon = concat(BASE_PATH,'2.jpg');
            when 3 then
                set _icon = concat(BASE_PATH,'3.jpg');
            when 4 then
                set _icon = concat(BASE_PATH,'4.jpg');
            when 5 then
                set _icon = concat(BASE_PATH,'5.jpg');
            when 6 then
                set _icon = concat(BASE_PATH,'6.jpg');
            else
                set _icon = concat(BASE_PATH,'1.jpg');
            end case;
            set _temp = round(rand()*10000+1000);
            set _price = _temp;
            set _temp = round(rand()*10000+1000);
            set _detail = concat(_temp,'-Apple/苹果 iPhone 7 Plus苹果7代7pluss国行美版三网5.5寸7p手机');
    
            # 插入数据
            insert into goods(name,icon,price,detail) value(_name,_icon,_price,_detail);
    
            # 修改次数
            set _i = _i + 1;
        end while;
    
        # 显示数据
        select * from goods;
    end
    //
    delimiter ;
    
    # 第六步: 调用存储过程 【根据自己需求添加对应个数即可】
    call add_goods(30);
    
    
    # goodslist.html文件
    {% load static %}
    
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>饿了吗 | 商品列表</title>
        <link rel="stylesheet" type="text/css" href="{% static 'elema/css/goodslist.css' %}">
    </head>
    <body>
        <h1>当前页: {{pageobj.number}}</h1>
    
        <!--显示内容-->
        <ul class="content">
            {% for goods in pageobj.object_list %}
                <li>
                    <div>
                        <img src="{{goods.icon}}">
                        <span> {{goods.name}} - ¥{{goods.price}}</span>
                    </div>
                    <p> {{goods.detail}} </p>
                </li>
            {% endfor %}
        </ul>
    
        <!--分页页码-->
        <ul class="pageview">
            {% for index in pageobj.paginator.page_range %}
                <!--当前页面-->
                {% if index == pageobj.number %}
                    <li class="active"> {{index}} </li>
                {% else %}
                    <li>
                        <a href="{% url 'elema:goodslist' index %}">{{index}}</a>
                    </li>
                {% endif %}
            {% endfor %}
        </ul>
    </body>
    </html>
    
    

    五、ajax请求

    • 概述
    网页中需要动态生成时,会向服务器请求对应JSON数据
    
    
    • 示例
    # urls.py文件
    url(r'^goodsjson/$',views.goodsjson, name='goodsjson'), # 商品列表json数据操作页面(ajax操作)
    url(r'^goodsinfo/$',views.goodsinfo, name='goodsinfo'), # 商品列表json数据
    
    
    # views.py文件
    # 商品列表json数据(ajax操作)
    def goodsjson(request):
        return render(request,'elema/goodsjson.html')
    
    # 返回商品列表json数据
    from django.http import JsonResponse
    def goodsinfo(request):
        # 所有商品数据
        alllist = Goods.objects.all()
    
        # 拼接成列表
        list = []
        for goods in alllist:
            list.append({'name':goods.name,'price':goods.price})
    
        return JsonResponse({'data':list})
    
    
    # goodsjson.html文件
    {% load static %}
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>商品列表JSON数据</title>
        <script type="text/javascript" src="{% static 'elema/js/jquery-3.1.1.min.js' %}"></script>
        <script type="text/javascript" src="{% static 'elema/js/goodsjson.js' %}"></script>
    </head>
    
    <body>
        <h1>商品信息列表</h1>
        <button id="bt">显示商品列表</button>
    
    </body>
    
    </html>
    
    
    # goodsjson.js文件
    $(function(){
        $('#bt').click(function(){
            // jquery中ajax快捷操作
            $.ajax({
                type:"get",
                url:"/elema/goodsinfo",
                dataType: 'json',
                success: function(data, status){
                    console.log(data);
    
                    // 获取返回的数据
                    var datasource = data['data'];
    
                    for(var i=0; i<datasource.length; i++){
                        var oP = document.createElement('p');
                        oP.innerHTML = datasource[i]['name'] + "  ¥" + datasource[i]['price'];
                        document.body.appendChild(oP);
                    }
                }
            });
        });
    });
    
    

    作者:西门奄
    链接:https://www.jianshu.com/u/77035eb804c3
    來源:简书
    简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

    相关文章

      网友评论

          本文标题:07-Django高级使用

          本文链接:https://www.haomeiwen.com/subject/vskbzftx.html