Django个人工作总结

Django个人工作总结

 

 

API:https://docs.djangoproject.com/zh-hans/2.1/

DCIM:https://www.dicomstandard.org/current/

ADMIN:https://www.cnblogs.com/caseast/p/5909987.html

 

POST请求要加csrf

页面竖直滚动

form表单提交遇到的问题

django模板for循环和表单提交

django传输数据限制

django上传文件

django返回ajax数据

django返回页面并渲染模板

django模板中使用富文本标签

django的HttpRequest

Django内置模板标签和过滤器

Django自定义模板【过滤器】

Django中混合使用artTemplate

Django--render()

Django--local()

日期格式处理

django order_by

django filter

shutil模块递归删除文件目录

Django 只查询单个字段

Django 查询结果返回前台出现' 或者 "

Django 批量插入

Django 原生SQL

Django 事务回滚

Django url传递参数

Django 生成和执行requirements.txt

Django 配置打印sql日志

Django 使用Oracle11g遇到的坑

Django 启动时执行任务

Django 如何优雅的停止

关于跨域请求session的问题

关于拦截器中修改response问题

 

 

 

 

POST请求要加csrf

最重要的:大脑不清晰,想用ajax请求将数据传递后台,但是还想跳转页面,这目前以我的技术还达不到。后台是没办法改变浏览器地址的,后台只能将数据渲染到页面上,而只有你浏览器访问页面了才看得到,不访问,后台怎么渲染你还是看不到,这就是后台不能帮你在浏览器跳转所导致的问题。所以只有修改浏览器地址了。

毛毛给的建议是使用window.location.href修改浏览器地址,细细想,如果我用ajax请求后台,将数据提交到后台后,然后将后台处理的数据渲染到另一个页面上,然后在ajax的success里使用window.location.href去修改浏览器地址,按理说应该也是行得通的,没试过。

最后我还是使用了form表单,将数据提交到后台的。

 

后台获取post请求要在方法上加注解。

from django.views.decorators.csrf import csrf_exempt

@csrf_exempt

页面:

 <!--病例表单-->
<form id="case_form">
   {% csrf_token %}
</form>

获取前台提交的数据:

request.POST

由于前台到后台django是使用QueryDict封装的,request.POST的结果是一个QueryDict,这是一个特殊的字典,有关该字典,可以看下面的链接了解。

https://www.cnblogs.com/scolia/p/5634591.html

 

还有就是后台提交的数据在前台变成乱码的问题,只需要在重定向后添加:

return render(request, 'survey/hys_result.html', context,content_type="application/json,charset=utf-8")

content_type="application/json,charset=utf-8" 即可,这是用于返回json格式的,如果不是用于ajax规定的json把application/json去掉即可。

 

ajax的post请求后台:

from django.shortcuts import render
from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt
import json


def index(request):
    return render(request, 'index.html')

@csrf_exempt
def from_case(request):
    if request.method == 'POST':
        sex = request.POST['sex']
        print(sex)
        return HttpResponse(json.dumps({'sex': 123}), content_type='application/json')

ajax js:

/*表单提交事件*/
$('#send').click(function () {
    var data = $('#from_case').serialize();
    $.ajax({
        type: 'POST',
        url: '/sdd/from_case/', // 链接地址以/开头以/结尾
        async:false,
        data: data,
        dataType: 'json',
        success: function (result) {
            console.log(result);
        },
        error:function (error) {
            console.log(error)
        }
    })
    return false; // 阻止button按钮的默认提交事件
})

请求路由:

from django.urls import path

from . import views

urlpatterns = [
    path(r'', views.index, name='index'),
    path(r'sdd/from_case/', views.from_case, name='from_case'),
]
app_name = 'sdd'

页面竖直滚动

健康测评-体质测试页面

每次点击当前li,页面会变长,但是滚动条不会自动向下滚动,所以每次都要手动向下拉,很烦人。

想做一个效果:每次点击当前li,页面自动向下滚动。

百度了怎么获取页面滚动条滚动的距离:

$(window).scroll(function(){
    //console.log(window.pageYOffset);
    pos = window.pageYOffset;
})

知道了每次滚动的距离是多少就好办了,只要我每次点击当前li,只要让滚动条自动向下前进一定的距离就可以实现想要的效果了,那怎么设置滚动条的距离?

百度:

var autoGo = function (pos) {
    $("html,body").animate({ scrollTop: pos },speed);
};

页面每次滚东pos距离,pos的单位是像素【字符串】,speed代表滚动的速度以毫秒级为单位的【是个数值】

 

具体代码:

var pos = 0;
$(window).scroll(function(){
    //console.log(window.pageYOffset);
    pos = window.pageYOffset;
})

var autoGo = function (pos) {
    $("html,body").animate({ scrollTop: pos },0);
};

//first代表第一次点击,第一次点击前进的距离多一些

if(first == 0){
    first++;
    pos = pos + 356 + 'px';
}else{
    pos = pos + 127 + 'px';
}
//console.log(pos);
autoGo(pos);

python web函数调用:与java类似

 

 

form表单提交遇到的问题

做表单提交时遇到的问题:在form上加onsubmit = "return check(this)",不进入check方法,check方法返回ture则提交表单,否则不提交。换了一种方式,使用submit按钮的onclick方法,但是有个要求就是submit按钮的id不能为"submit",否则报form.submit();is not a function

 

 

django模板for循环和表单提交

for循环中我需要获取当前的序号:

{{forloop.counter0}}

代表以0开始

{{forloop.counter}}

代表以1开始。

for循环中使用if判断当前序号是奇数偶数:

{% if item.importent == True %}
    {% if forloop.counter0|divisibleby:2 %}
        <li class="title">{{tent}}</li>
    {% else %}
        <li>{{tent}}</li>
    {% endif %}
{% else %}
    <li>{{tent}}</li>
{% endif %}

3.form表单获取表单内input的值:

var form = document.getElementById("myfrom");
if(form.sex.value == ''){
    alert("请选择性别!");
    return false;
}

使用该form对象.input的name.value

 

一个form表单提交的实例:

<form action="/survey/survey_hys_result" method="post" id="myfrom">
******

<input type="submit" id="sub" value="测试中...">
</form>

sub.onclick = function() {
    if(isLast < 59) {
        alert("请先完成测试");
        if(isLast == 0){
            pos = 0 + 'px';
            autoGo(pos);
        }else{
            pos = 356 + 127*isLast + 'px';
            autoGo(pos);
        }
        return false;
    }
    var form = document.getElementById("myfrom");
    if(form.sex.value == ''){
        alert("请选择性别!");
        return false;
    }
    if(form.age.value == ''){
        alert("请选择年龄!");
        return false;
    }
    form.submit();
    return ture;
}

django传输数据限制

我在使用post传递dicm影像数据时遇到的问题:Request body exceeded settings.DATA_UPLOAD_MAX_MEMORY_SIZE,由于默认django允许post传递的数据量为2.5MB

setting中可以使用如下:设置传递的数据量为5MB

DATA_UPLOAD_MAX_MEMORY_SIZE = 5242880 

django上传文件

在属性upload_path中配置上传路径

要在settings里配置media上传文件路径,当上传文件时它会自动在项目中创建/static_in_env/upload路径,上传的文件将放在upload/dcm下

上传service:

在这里说一下我的上传路径也必须要前端能访问,不然前端不能通过url拿到dcm文件,也百度了,也看小叶之前代码的配置了,才知到其实不用那么复杂。首先:由于我的上传路径是和实体类绑定的,所以我必须要使用MEDIA_ROOT

实体属性绑定:


上传路径的等于MEDIA_ROOT + dcm/。

其次是前端访问dcm静态文件路径:

直接配置:

MEDIA_URL即可。然后在urls里配置:

先要导入两个包,然后配置两个静态访问路径。前端访问方式:


可以直接使用/upload/访问其下的文件

 

参照网址:

上传service代码:https://blog.csdn.net/wanpengsen4890/article/details/81914135

有关django表单对象:https://www.cnblogs.com/zongfa/p/7709639.html

media上传路径的配置https://www.cnblogs.com/yinxin/p/9076894.html

MEDIA_ROOT, MEDIA_URL, STATIC_ROOT, STATIC_URL的介绍:

https://blog.csdn.net/geerniya/article/details/78958243

 

 

django返回ajax数据

django返回页面并渲染模板

django模板中使用富文本标签

{{ if info.就诊.重点检查项目 }}
    <div class="describe-project">
        <p class="item-name">重点检查项目</p>
        <p class="item-content padding-l-20">
            {{ each info.就诊.重点检查项目 val key }}
                {{@ val }}
            {{ /each }}
        </p>
     </div>
{{ /if }}

// 也可以直接在script中使用
<script>
    console.log({{info}})
</script>

django的HttpRequest 

由于在访问详情页面时我使用的传参方式是:


如上,前端如下

但是我拿到详情页后又要去处理这个dcm文件(split操作),所以我又要将这个dcm的id在传给split,我尝试了几种写法,如:

结果都是404,我感觉可能有问题的就是这个<int:id>了,而且我这样写浏览器端的路径是相对路径:

http://localhost:8000/12/detail/split

http://localhost:8000/12/detail/12/split

根本和我的url匹配不上,最后我先从浏览器端开始,使用绝对路径,所以我就用到了request对象,其document地址为:https://docs.djangoproject.com/en/2.1/ref/request-response/

我的处理如下:


这个即可以在后台获取传到前台也可以在前台使用{{ request.scheme }}和{{ request.get_host }}获取,我是在后台获取传到前台的

 

我改变了方式,不在url的路径里传递参数了,因为我是异步请求,可以直接将id使用data传过去。这样就解决了所有问题。

 

 

Django内置模板标签和过滤器

针对于使用render返回的数据,如果在前台直接拿的话是需要转义和转成json对象的。

def index(request):
    """
    患者病例系统的首页
    :param request:
    :return:
    """
    data = list(DICT_JYJC.objects.values())
    return render(request, 'index.html', {'list': data})

script标签中:

<script>
    var data = '{{ list }}';
    data = data.replace(/&#39;/g,'"');
    console.log(data);
    console.log(JSON.parse(data));
</script>

自己好久没用django了,也忘记了django有哪些模板标签了,使用模板标签的话,直接就可以遍历,并不需要多此一举在script里做处理。在此加一笔,记录。推荐好文

<span class="fz-input">
    <input type="text" class="input-line"
           style=" 150px;text-align: center">
    <select>
        {% for foo in list %}
            <option>{{ foo.VAL }}</option>
        {% endfor %}
    </select>
</span>

Django自定义模板【过滤器】

首先说说我自定义的普通for循环【遍历两个等长列表】:

for(int i=0;i<list1.lenght;i++){
    print(list1[i]);
    print(list2[i]);
}

django模板中只有

{% for txt in list %}
    {{ txt }}
{%endfor%}

的实现

而此时我要遍历两个等长列表,麻烦来了,我无法直接使用forloop.count0作为列表的索引使用

即:list[forloop.count0]不支持。

查阅网上的做法基本没有,没办法,最后选择了自定义模板方法:

1.在应用中创建templatetags文件夹,该文件夹下要包含一个_init_.py文件和一个存放你自定义模板方法的地方:

 

图中:我app名字为survey,存放我自定义模板方法的地方为survey_dealfor.py。

看一下survey_dealfor.py:

from django import template

register = template.Library()

@register.filter(name='dfor')
def dfor(index, list):
    print(index)
    print(list)
    return list[index]

dfor方法传来两个参数,一个是索引,一个是列表,返回该列表在该索引处的值。

然后在settings.py中:

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')],
        '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',
            ],
            'libraries': {
                        'survey_dealfor': 'survey.templatetags.survey_dealfor',
                    }
        },
    },
]

添加libraries配置项,survey_dealfor就是你马上即将要在html中load的名字,该名字对应着你自定义模板的路径。

看一下html:

{% for litext in item.selection %}
    <span>
        <a href="#question2" class="question-two-picture">
            <span class="picture-text">{{litext}}</span>
            <img class="img-content" src="/static/survey/images/{{ forloop.counter0|dfor:item.selectImg }}">
        </a>
    </span>
{% endfor %}

这样就ok了,然后你一定要重启一次服务才行。这样我实现了我想要的效果,没毛病。

 

你可能会遇到问题看这里:

https://stackoverflow.com/questions/40686201/django-1-10-1-my-templatetag-is-not-a-registered-tag-library-must-be-one-of/42881074

 

Django中混合使用artTemplate

由于django自带的模板标签语言和artTemplate有差异,如果直接在script里嵌入artTemplatedjango会不能识别而报错,要在django中使用artTemplate要加以下条件:

<script id="temptab" type="text/html">
        {% verbatim %}
        {{ each list as v i }}
        <tr id="'{{ v.id }}'">
            <td>
                {{if v.is_files}}
                    <a href="javascript:;" onclick="dir_detail('{{ v.id }}',1)">
                        <span class="glyphicon glyphicon-folder-close icon-dir" aria-hidden="true"></span>
                        <span class="fename">{{ v.name }}</span>
                    </a>
                {{ else }}
                    <span class="glyphicon glyphicon-file" aria-hidden="true"></span>
                        {{ if v.dir_rank == 2 }}
                            <span class="fename"><a href="dcmDetail/?id={{ v.pid }}&flag=0">{{ v.name }}</a></span>
                        {{ else }}
                            <span class="fename"><a href="dcmDetail/?id={{ v.pid }}&flag=1">{{ v.name }}</a></span>
                        {{ /if }}
                {{/if}}
            </td>
            <td class="feinfo">{{ v.info }}</td>
            <td>{{ v.time | dateFormat:'yyyy-MM-dd h:m:s' }}</td>
            <td>
                {{ if v.dir_rank == 0 }}
                    <a href="javascript:;" data-toggle="modal" data-target=".edit-dir-modal"
                       onclick="editDir('{{ v.id }}','{{ v.name }}','{{ v.info }}')">
                        编辑
                    </a>
                    <a href="javascript:;" data-toggle="modal" data-target=".add-dir-modal"
                       onclick="addSecDir('{{ v.id }}','{{ v.name }}')">
                        创建子目录
                    </a>
                {{ /if }}
                {{ if v.dir_rank == 1 }}
                    <a href="javascript:;" data-toggle="modal" data-target=".add-file-modal"
                       onclick="addNewFiles('{{ v.id }}','{{ v.name }}')">
                        上传DCM文件
                    </a>
                    <a href="javascript:;" data-toggle="modal" data-target="#splitModal" data-keyboard="false"
                       data-backdrop="static" onclick="split('{{ v.id }}')">
                        分割
                    </a>
                {{ /if }}
                {{ if v.dir_rank == 2 }}
                    <a href="dcmDetail/?id={{ v.pid }}&flag=0">show</a>
                {{ else if v.dir_rank == -3 }}
                    <a href="dcmDetail/?id={{ v.pid }}&flag=1">show</a>
                {{ /if }}
                {{ if v.dir_rank == 0 || v.dir_rank == 1 || v.dir_rank == -1 || v.dir_rank == -2 }}
                    <a href="javascript:;" onclick="del('{{ v.id }}',this)">
                        删除
                    </a>
                {{ /if }}
            </td>
        </tr>
        {{ /each }}
        {% endverbatim %}
    </script>

你要将你的artTemplate使用{% verbatim %}{% endverbatim %}包裹起来,这样django就不会编译这段代码,然后使用后台传递来的数据,将你的数据嵌入你写的模板中:

$.ajax({
            type:'post',
            url:'dir_detail/',
            data:{id:id, flag:flag},
            dataType:'json',
            success:function(data) {
                var list = [];
                for (var i = 0;i<data.length;i++) {
                    var dt = data[i];
                    dt.fields.id = dt.pk;
                    list.push(dt.fields);
                }
                var content =  template('temptab',{'list':list});
                $("#file_content").html(content);
                if(list.length != 0) {
                    $(".pre-dir").data('id',list[0].pid);
                }
            }
    });

如上:使用template方法时,你必须指定一个json对象,‘list’对应模板的list,如果你直接传递list,像这样:

var content =  template('temptab',list);

你将得不到任何信息。

 

Django--render()

django携带数据返回页面,可直接将数据渲染到页面

仔细看,你会发现使用render可以直接传递没有序列化的实体,而且他能够恰好的映射到模板上。而使用:

HttpResponse时如果是传递普通的字符串json对象,可以直接上传,但是要上传实体时就要将实体序列化后才能上传,不然就报错,说不能上传没有序列化的数据。

 

 

Django--local()

 

 

日期格式处理

实体日期类型:

更改类型【dateTime.strftime】:

django order_by

如上:查询数据库,安装is_files和time两个字段排序,其中is_files是降序,time是升序。即:加个负号代表是降序,默认是使用升序

 

django filter

相当于:

select * from db where name = 'split' and pid = '909218329989'

shutil模块递归删除文件目录

import shutil
shutil.rmtree(path)

Django 只查询单个字段

 

https://www.jianshu.com/p/7c7645674ae0

 

Django 查询结果返回前台出现' 或者 "

解决方案:

{{ data|safe }}

Django 批量插入

# save 补充条件:批量插入
        bd_bctj_list = []
        for o in other:
            bd_bctj = BD_BCTJ()
            bd_bctj.BLID = blid
            bd_bctj.JLID = jlid
            bd_bctj.ZZID = o['zzid']
            bd_bctj.ZZXXID = o['zzxxid']
            bd_bctj_list.append(bd_bctj)
        BD_BCTJ.objects.bulk_create(bd_bctj_list)

Django 原生SQL

import django
from django.db import connection
import logging
import traceback
logger = logging.getLogger("django")

@staticmethod
def execute(sql, params=None, _one=False, _dict=False):
    """
    执行一条SQL
    :param sql: example: 'select * from table where name = %s'
    :param params: sql参数
    :param _one: 默认使用fetchall,若_one=True则使用fetchone
    :param _dict: 封装成dict形式
    :return:
    """
    try:
        with connection.cursor() as cursor:
            cursor.execute(sql, params)
            if _one:
                result = cursor.fetchone()
            else:
                result = cursor.fetchall()
            if _dict:
                col_names = [desc[0] for desc in cursor.description]
                result = dict(zip(col_names, result))
    except django.db.DatabaseError as e:
        logger.error(traceback.format_exc())
        raise e
    return result
    
    
    
    
# 如果在Python中和Mysql一起使用时,可以直接用下面方式 
import MySQLdb   
conn = getConnection(dbparams)
cursor=conn.cursor(cursorclass = MySQLdb.cursors.DictCursor);
vreturn=cursor.execute(sql)

Django 事务回滚

from django.db import transaction

在需要使用事务的地方:
if exist == False:
    # use transaction
    with transaction.atomic():
        # write files to dir
        dest = open(file_path, 'wb+')
        for chunk in f.chunks():
            dest.write(chunk)
        dest.close()
        # get dcm rank
        dcm_rank = -1
        image = sitk.ReadImage(file_path)
        keys = image.GetMetaDataKeys()
        for key in keys:
            if key == '0020|0013':
                dcm_rank = image.GetMetaData(key)
        # write db
        file = createFiles(
            {'pid': dir_id, 'name': f.name, 'info': filesinfo, 'dir_rank': 3, 'dcm_rank': dcm_rank,
             'is_files': False, 'path': dir.path + f.name})
        file.save()
else:
    ...

如上我需要将上传dcm文件和创建dcm实体插入数据库这两个需要同步进行,添加事务只需要使用:

with transaction.atomic():
    #在这里写需要同步的东西

Django url传递参数

一个参数:

多个参数使用传统方式传递:

使用GET.get方式获取

 

更多参数:

https://www.cnblogs.com/lixiang1013/p/7748156.html

 

 

Django 生成和执行requirements.txt

生成【在manage.py同目录下执行】:

pip freeze > requirements.txt

执行【在manage.py同目录下执行】:

pip install -r requirements.txt

Django 使用Oracle11g遇到的坑

参考链接:https://www.jianshu.com/p/440c726cc516

1:

Django要使用oracle首先要去下载对应python版本和操作系统的oracle的驱动(cx_Oracle),由于当前我使用的Python版本是3.6.6服务器oracle版本是11g,查阅官网关于数据库支持这块,发现支持oracle11g的django版本在2.0以下,如果是2.0以上会报错cx_Oracle.DatabaseError: ORA-02000: missing ALWAYS keyword】,2.0只支持oracle12c极其以上版本,没办法我只好更换了我的Django版本为低版本。然后我在pypi官网上翻找了cx_Oracle【https://pypi.org/project/cx-Oracle/7.2.3/#files】驱动历史版本,发现只有cx-Oracle==5.3支持我当下情况:

于是我使用pip安装,

pip install cx-Oracle==5.3

结果报了一个奇怪的错误,没办法我只好手动的去下载上图我标记的那个文件,下载后手动安装时我又遇到了一个特别恶心的问题就是这个exe安装时会自动读取Python的安装路径,但是由于我使用的是Anaconda去管理的Python版本,所以这个exe根本读取不了我的Python安装路径,而且还不能自己手动输入自己的Python安装路径,没办法,我试图在环境变量里配置Anaconda中已经下载的python3.6.5,再次安装这个exe还是不行!没办法,我只好老老实实的去官网上在下载一个Python3.6.6安装包,在本地安装了一下并配置好环境变量,在安装那个exe文件,问题解决了。到此我也仅仅只是安装了oracle的数据库驱动。

接下来开始下载对应服务器的oracle客户端instantclient_11_2,把其中的oci.dll、oraocci11.dll、oraociei11.dll三个文件拷贝到python3.6.6环境下lib/sit-packages目录下

下面我开始切换我项目的环境,由于之前我项目里使用的是Anaconda里的py365创建的虚拟环境,现在oracle的驱动安装在本地Python3.6.6中了,所以要将项目环境切换到刚安装的Python3.6.6里,经过一番折腾(还好项目不大),终于切换完了,我写了一个测试文件,测试一下这个cx_Oracle驱动能不能使用:

import cx_Oracle

# Create your tests here.
if __name__ == '__main__':
    '''Hello cx_Oracle示例:
    conn = cx_Oracle.connect("username/pwd@localhost/dbname")
    cur = conn.cursor()
    try:
         #cur.execute("insert into bd_hzbl values(3,1,22,'a','b','c','d','e','f','g',null,null)")
        #conn.commit()
        
         cur.execute('select * from bd_hzbl')
         data = cur.fetchall()
         print(data)
    finally:
        cur.close()
        conn.close()

还好还好,对于插入和查询都没问题,这下我就放心了,开始在我的项目里使用oracle了【在此之前我下载了oracle的客户端64位的并配置好了环境变量,因为我要连接服务器上的数据库】。

常用操作:

#第一步:创建基本model:

python manage.py migrate

#第二步:初始化自己的model

python manage.py makemigrations TestModel

#第二步:初始化数据库表

python manage.py migrate TsetModel

如果以上两步出现了问题,最好看看你有没有oracle客户端,有没有oracle配置环境变量。

然后校验我们的model:

python manage.py inspectdb 表名 > aaa.py

一路坎坷,各种百度解决问题,现在到了开始在项目里使用它了,我创建了一个简单的表单,和一个model:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

'实体'
from django.db import models

# 患者病例
class BD_HZBL(models.Model):
     ID = models.AutoField(primary_key=True)
    XB = models.IntegerField()  # --性别 0-男 1-女
    NL = models.IntegerField()  # --年龄
    TSSQ = models.CharField(max_length=2)  # --特殊时期
    ZS = models.CharField(max_length=200)  # --主诉
    XBS = models.CharField(max_length=200)  # --现病史
    JWS = models.CharField(max_length=200)  # --既往史
    TGJC = models.CharField(max_length=200)  # --体格检查
    FZJC = models.CharField(max_length=200)  # --辅助检查
    BZ = models.CharField(max_length=200)  # --备注
    CJSJ = models.DateTimeField()  # --创建时间 auto_now_add=True
    XGSJ = models.DateTimeField()  # --修改时间 auto_now=True

    class Meta:
        db_table = 'BD_HZBL'

然后请求提交表单,在处理器中将这个表单数据赋值给实体属性,然后save实体,这是一个正常的操作:

# 保存一个实体类
bd_hzbl = BD_HZBL()
bd_hzbl.ID = 3
bd_hzbl.XB = 1  # sex
bd_hzbl.NL = 23  # age
bd_hzbl.TSSQ = 'a'  # rs + ',' + br
bd_hzbl.ZS = 'b'  # zs
bd_hzbl.XBS = 'c'  # xbs
bd_hzbl.JWS = 'd'  # jws
bd_hzbl.TGJC = 'e'  # tgjc
bd_hzbl.FZJC = 'f'  # jcxm
bd_hzbl.BZ = 'g'  # jcjg
bd_hzbl.CJSJ = timezone.now()
bd_hzbl.XGSJ = timezone.now()
bd_hzbl.save()

但是在项目里就不正常了,报了一个错误:

django.db.utils.DatabaseError: OCI-22061: invalid format text [999999999999999999999999999999999999999999999999999999999999999]

但是我如果使用:

all = BD_HZBL.objects.all()

它有神奇的给我返回了三个数据【我测试cx-Oracle时插入的三个】。这明显的是说明我的实体类写的肯定有一些问题的!

到此,我彻底卡住了,网上关于这个错误的问题寥寥无几,最后我在国外的一篇文章上找到了擦边答案:https://sourceforge.net/p/cx-oracle/mailman/message/26209197/

这篇文章讲的是关于我oracle字符集编码的问题,但是最后我也尝试设置我本地客户端字符集编码了(和服务器同步),最后还是没能解决。

我开始针对我的字段进行测试,我尝试删除所有字段(并重新生成表),仅仅保留主键字段,奇迹的是我竟然save成功了!!!数据库里出现了ID字段为1的数据,这令我欣喜若狂,接下来我又开放了一个IntegerFiled字段(重生表),不幸的是又出现了那个OCI-22061的错误!我屏蔽IntegerField字段开发CharFiled又成功插入了!我赶紧跑到django1.11官网上查找有关IntegerField的说明,并没有我所期望的信息,至此我知道了使用IntegerField是不行的,但是我没有更好的办法了,官网上说能用,但是在我这不能用。无奈,我将IntergerField字段都改成了CharField,这个问题算是心有不快的勉强解决了。

 

 

 

Django 启动时执行任务

官网介绍:https://django.readthedocs.io/en/latest/ref/applications.html

网友使用:http://www.cnblogs.com/xjmlove/p/10087053.html

打印两次问题:https://stackoverflow.com/questions/37441564/redefinition-of-appconfig-ready

 

如果你想在你的应用程序启动时执行某件事,django提供了一个很好的方式就是在你的app应用程序里的apps.py程序里重写AppConfig超类的ready()方法

看到官网的说明我就直接尝试了重写ready()方法,如下:

# sdd/apps.py
from django.apps import AppConfig
from django.utils.module_loading import autodiscover_modules


class SddConfig(AppConfig):
    name = 'sdd'

    def ready(self):
        print(1)
        autodiscover_modules("***.py") # 用于启动时执行某个文件,***.py和apps.py同目录下

然后启动django,并没有执行我的ready()方法,百思不得其解,去网上查找也没有相关的说明,我打断点压根就不跳到我的断点处,虽然我可以用其他方式去在django启动时执行我的任务(就是在sdd/views.py中的开始处写我的任务,或在urls中写我的任务),但是我有洁癖,感觉那样很不爽。抱着一定要解决这个问题的态度,又跑去官网查看,无意间我往上翻了翻,哦!原来不仅要重写ready()方法还要有一些其他东西要配置!!!

按照官网说的,我在我的app下(即sdd),新建了一个__init__.py文件,在其中添加一行如下:

default_app_config = 'sdd.apps.SddConfig'

代码目录看下图:

然后再次启动django,问题解决,控制台打印出了两个1,为什么会打印出两个1我也大概知道:

python manage.py runserver --noreload

至此这个问题已经解决了。

 

 

Django 如何优雅的停止

终止uwsgi

自强学堂关于发送给进程的信号

 

 

关于跨域请求session的问题

先读

 

 

关于拦截器中修改response问题

在拦截器中修改response:

class ParamsMiddleWare(MiddlewareMixin):
    """
    AOP:处理请求参数
    """

    def process_response(self, request, response):
    """
    AOP:拦截response,使用AES加密返回状态码为200的结果
    :param request:
    :return:
    """
    if request.path.startswith('/api/'):
        if response.status_code == 200:
            resp = HttpResponse(content=encrypt_data(KEY.encode('utf-8'), response.content.decode('utf-8')),
                                content_type='text/plain')
            return resp
    return response

如上代码所属,我在拦截器中重新定义了一个新的response返回,这一切看起来没什么问题,在django的拦截器中这么定义也很正常,而且我在postman里测试也一切都没问题,有问题的是在前端axios的全局拦截器里竟然在错误的回调函数里返回给我一个如下错误:

Failed to load resource: net::ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_LENGTH
Uncaught (in promise) Error: Network Error
    at createError (webpack-internal:///./node_modules/axios/lib/core/createError.js:16)
    at XMLHttpRequest.handleError (webpack-internal:///./node_modules/axios/lib/adapters/xhr.js:83)

这就让我很郁闷了啊,如果我不新建一个HttpResponse返回,之间用参数中的response返回,axios能拿到数据且不会报任何错误。细想这肯定是因为两个response之间有差异导致的,到底有什么差异?我在debug发现二者的_headers属性不一样,于是我尝试之间将参数里的response的_headers赋值给新建的HttpResponse对象,这导致Django无法正常返回响应。我向肯定是我的操作姿势不对,在官网API中找到了一个可以设置header的方法

resp.setdefault(header, temp)

# resp.setdefault('content-type', 'application')

这个方法让我无比的吐槽,且看一下源码部分:

def __setitem__(self, header, value):
    header = self._convert_to_charset(header, 'ascii')
    value = self._convert_to_charset(value, 'latin-1', mime_encode=True)
    self._headers[header.lower()] = (header, value)


def setdefault(self, key, value):
    """Set a header unless it has already been set."""
    if key not in self:
        self[key] = value

调用setdefault没啥问题,问题出在__setitem__上,这个方法竟然将我设置的header的值组合成了(header,value),这尼玛,导致我新建的response和参数里的response不一样!

 

前进时,请别遗忘了身后的脚印。
原文地址:https://www.cnblogs.com/liudaihuablogs/p/13463174.html