zoukankan      html  css  js  c++  java
  • 那些在django开发中遇到的坑

    1. 关于csrf错误

    CSRF(Cross-site request forgery)跨站请求伪造,也被称为“one click attack”或者session riding,通常缩写为CSRF或者XSRF,是一种对网站的恶意利用。

    django中自带了防止CSRF攻击的手段,在form表单的action属性中,GET时不需要CSRF认证,而POST时需要。

    一般而言,有两种解决办法:

    ① 启用csrf认证

    • 在settings.py中启用中间件django.middleware.csrf.CsrfViewMiddleware

    • 在views.py的render_to_response中,用RequestContext代替默认的Context,如下:

    return render_to_response('a.html', data, context_instance=RequestContext(request, processors=[my_fun])) 

    注:若想要重定向到一个action,则用HttpResponseRedirect

    • 在模板文件中的 form 表单内添加 {% csrf_token %} 

    ② 关闭csrf认证

    • 注释掉django.middleware.csrf.CsrfViewMiddleware即可

    2. 后台传列表或者字典给js函数

    这里容易遇到两个难题,一是中文会显示成unicode形式,二是引号会被转义,使得js函数出错

    ① 无论是字典还是列表,传给js都可以用json来处理:

    import json
    test_dict = {
        "weather": ["sun", "rainy", "windy"],
        "mood": ["happy", "sad"]
    }
    
    json_str = json.dumps(test_dict, ensure_ascii=False)
    View Code

    注:其中的ensure属性是为了解决中文编码问题

    ② 在django中有专门禁止转义的方式,只需在js函数用标签围住相关代码块即可:

    <script>
        function test_fun() {
            {% autoescape off %}
            var json_obj = {{ dict_json }}
            {% endautoescape %}
        }
    </script>
    View Code

     3. 文件上传与下载

    进行文件上传的时候我遇到很多错误,以下是简单的总结:

    • 在form中方法必须问POST

    • 在form中要加入:enctype="multipart/form-data"

    • 后台用name属性接受前端的文件,以下为一种简单接受文件的写法:

    myfile = request.FILES.get("file_name", None)
    
    if myfile != None:
        des_dir = "/home/me/path/filename"
        des_file = open(des_dir, 'wb+')
        
        for chunk in myfile.chunks():
            des_file.write(chunk)
    
        des_file.close()
    View Code 

    文件下载则相对容易很多,以excel为例:

    def write_excel():
        #返回未保存的workbook
        pass
        
    
    def main_process(request):
        response = HttpResponse(content_type='application/vnd.ms-excel')
        response['Content-Disposition'] = 'attachment; filename=test.xlsx'
    
        wb = write_excel()
        wb.save(response)
    
        return response
    View Code

    另外提供一个js获取文件后缀名的函数:

    <!-- 假设file的id为upload_file -->
    <script>
        function getFileType {
            //这里是jquery的用法,自行去了解
            var file = $('#upload_file').val();
            return file.replace(/.+./, '');
        }
    <script>
    View Code

     4. python跨目录imprt模块

    之前我写了一些模块,在别的目录下,想引用它们却一直出错,找了一些资料,总结了几个实用的Tips:

    ① 若被引用的模版在更低的目录中,如子目录(sub_dir),则需要在该子目录中建立__init__.py的空文件,则可以直接在文件中:

     import sub_dir.model_name 

    ② 若其在父目录,则需要:

    import sys
    sys.path.append("..") 
    import model_name
    View Code

     5. 后台获取前端select multiple的数据

    前端代码如下:

    <select mutiple="multiple" id="select">
        <option value="0">0</option>
        ...
    </select>
    <!-- 隐藏的表单,用来传给后台 -->
    <input type="text" style="display:none" id="select_input "name="select_str">
    
    <!-- js/jquery部分-->
    <script>
        $(document).ready(function(){
            $('#select').change(function(){
                var objs = $('#select').val();
                var result = "";
                for(var key in objs) 
                    result = result + "," + objs[key];
                if(result == "")
                    $('#select_input').val("");
                else
                    $('#select_input').val(result.substr(1));
            });
        });
    </script>
    View Code

      后台只需要执行(若是GET方法):

     select = request.GET.get("select_str", "") 

    注:有时候用到getElementsByName的时候,需要主要得到的是一个数组,因为html中名字可以出现多次

    6. 善于使用logging模块

    ① django中在settings.py中有个LOGGING的配置

    LOGGING = {
        'version': 1,
        'disable_existing_loggers': False,
        'filters': {
            'require_debug_true': {
                '()': 'django.utils.log.RequireDebugTrue',
            }, # 针对 DEBUG = True 的情况
        },
        'formatters': {
            'standard': {
                'format': '%(levelname)s %(asctime)s %(pathname)s %(filename)s %(module)s %(funcName)s %(lineno)d: %(message)s'
            }, # 对日志信息进行格式化
            # INFO 2016-09-03 16:25:20,067 /home/ubuntu/mysite/views.py views.py views get 29: some info...
        },
        'handlers': {
            'mail_admins': {
                'level': 'ERROR',
                'class': 'django.utils.log.AdminEmailHandler',
                 'formatter':'standard'
            },
            'file_handler': {
                 'level': 'DEBUG',
                 'class': 'logging.handlers.TimedRotatingFileHandler',
                 'filename': '/tmp/byod/byodadmin/byod.admin.log',
                 'formatter':'standard'
            }, # 用于文件输出
            'console':{
                'level': 'INFO',
                'filters': ['require_debug_true'],
                'class': 'logging.StreamHandler',
                'formatter': 'standard'
            },
        },
        'loggers': {
            'django': {
                'handlers' :['file_handler', 'console'],
                'level':'DEBUG',
                'propagate': True # 是否继承父类的log信息
            }, # handlers 来自于上面的 handlers 定义的内容
            'django.request': {
                'handlers': ['mail_admins'],
                'level': 'ERROR',
                'propagate': False,
            },
        }
    }
    View Code

     重要的是handlers和loggers,handler定义了log文件所在位置,而一个logger可以将多个handler加入其中,我们在代码中使用只需:

    import logging
    logger = logging.getLogger("django") # 为loggers中定义的名称
    logger.info("some info...")
    View Code

    ② 不使用django中的配置,直接封装成一个函数:

    def initRotateLog(log_file="/path/name.log" , log_name="" , level=logging.DEBUG, max_bytes=100*1024*1024 , backup_count = 5 ):
        handler = logging.handlers.RotatingFileHandler(log_file, max_bytes, backupCount)
        fmt = '...' #自己去查相关资料
        formatter = logging.Formatter(fmt)   
        handler.setFormatter(formatter)      
        logger = logging.getLogger(log_name)    
        logger.addHandler(handler)           
        logger.setLevel(log_level)
        return logger
    View Code

     使用的时候直接这样用:

    from ... import  * #自己引入那个函数模块
    
    logger  = initRotate("/path/somepath/file.log")
    logger.info("lalala")
    View Code

     7. xlwt的坑

    在将大量数据(超过10w)写入到excel中,xlwt让我痛苦不堪,因为xlwt只支持写到的记录为65535条,多了便需要新建一个sheet或者重新写一个文件,但是我还是想直接写在一页,这个时候,我发现了另外一个模块:openpyxl(官方文档)

    怎么安装就不说了,很容易,这里介绍一下它的很常见的用法:

    from openpyxl import load_workbook #
    from openpyxl import Workbook #
    
    #读的方法
    workbook = load_workbook(file_name)
    sheet1 = workbook.active #正在活动的sheet
    
    #遍历得到每行第一个单元格的值
    for row in sheet1.rows:
        cell = row[0].value
        
    
    #写的方法
    workbook = Workbook()
    sheet1 = workbook.active
    sheet1.title = "Sheet1"
    
    #写入100行100列数据,全是1
    for row_index in range(1, 101):
        for col_index in range(1, 101):
            sheet1.cell(row=row_index, column=col_index).value = 1
    #写入文件
    workbook.save(file_name)
    View Code

    8. 关于datetimepicker的使用

    官方的datetimepicker貌似能够显示秒,但是那个秒不能用户操纵,于是我找了好久,找到一个包,里面有js和css等文件,还有一个demo.html的demo文件,效果如下:

    插入一个示例代码:

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8">
        <title>datetimepicker示例</title>
        <link type="text/css" href="css/jquery-ui-1.11.4.css" rel="stylesheet" />
        <link type="text/css" href="css/jquery-ui-timepicker-addon.css" rel="stylesheet" />
        <script type="text/javascript" src="js/jquery-1.11.1.js"></script>
        <script type="text/javascript" src="js/jquery-ui-1.11.4.js"></script>
        <script type="text/javascript" src="js/jquery-ui-timepicker-addon.js"></script>
        <script type="text/javascript" src="js/jquery-ui-timepicker-zh-CN.js"></script>
    </head>
    <body>
        <input type="text" id="time_test"  class="ui_timepicker">
    
    <script>
        jQuery(document).ready(function() {              
            $(function() {
                $.datepicker.regional['zh-CN'] = {
                    changeMonth: true,
                    changeYear: true,
                    clearText: '清除',
                    clearStatus: '清除已选日期',
                    closeText: '关闭',
                    closeStatus: '不改变当前选择',
                    prevText: '<上月',
                    prevStatus: '显示上月',
                    prevBigText: '<<',
                    prevBigStatus: '显示上一年',
                    nextText: '下月>',
                    nextStatus: '显示下月',
                    nextBigText: '>>',
                    nextBigStatus: '显示下一年',
                    currentText: '今天',
                    currentStatus: '显示本月',
                    monthNames: ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'],
                    monthNamesShort: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12'],
                    monthStatus: '选择月份',
                    yearStatus: '选择年份',
                    weekHeader: '',
                    weekStatus: '年内周次',
                    dayNames: ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'],
                    dayNamesShort: ['周日', '周一', '周二', '周三', '周四', '周五', '周六'],
                    dayNamesMin: ['', '', '', '', '', '', ''],
                    dayStatus: '设置 DD 为一周起始',
                    dateStatus: '选择 m月 d日, DD',
                    dateFormat: 'yy-mm-dd',
                    firstDay: 1,
                    initStatus: '请选择日期',
                    isRTL: false
                };
            });
            $(function() {
                $.datepicker.setDefaults($.datepicker.regional['zh-CN']);
                $(".ui_timepicker").prop("readonly", true).datetimepicker({
                    defaultDate: $('.ui_timepicker').val(),
                    dateFormat: "yy-mm-dd",
                    showSecond: true,
                    timeFormat: 'HH:mm:ss',
                    stepHour: 1,
                    stepMinute: 1,
                    stepSecond: 1,
                    forceParse: true
                });
            });
        });
    </script>
    </body>
    
    </html>    
    View Code

    这个包的下载地址在这里,点击下载

      未完待续...

  • 相关阅读:
    学习进度报告2021/4/5
    学习进度报告2021/4/4
    学习进度报告2021/4/3
    学习进度报告2021/4/2
    学习进度报告2021/4/1
    学习进度报告2021/3/31
    《学会提问》读书笔记3
    学习进度报告2021/3/30
    MySQL入门——如何进行主从配置
    MySQL入门详解——事务、锁、优化
  • 原文地址:https://www.cnblogs.com/vachester/p/7224572.html
Copyright © 2011-2022 走看看