• 基于Django的后台支撑与基于JS、HTML前台之间的交互探讨


    记录一个关键问题,导出的models.py可能跟编译器有关或它默认的就是utf16,使用manage.py进行运行可能不会发生错误,但是使用uwsgi进行运行会报错!!!所以导出后的models.py要将编码转化为utf8的格式。

    这个错误发生于uwsgi的启动阶段,直接进入页面会在页面显示如下错误。

    --------------------------------------------------------------------------------------

    django使用的设计模式是MTV(models/temples/views)模式

    目前我工作所使用的django使用方式并没有使用model,目前处于摸索阶段,不过先写出数据库反向输入model的方法:

    python manage.py inspectdb > models.py

    先进入manage.py所在的目录,然后根据你要操作的app进行输出,我这边manage.py与models.py在同一目录,所以只需要写名字即可。

    目前我工作使用的模式是前台用js和html支撑,然后后台由python支撑,起初项目启动时只对MTV一知半解,后面发现解耦的关键性作用,可是呢,问题是目前的代码情况来说,并不构成解耦,光js返回数据与前台之间就可能存在一定的关联,很难完整解耦。

    因此突然感觉可能是models没有使用的问题,所以在此稍加探索。

    ----------------------------------------------------------------------------------------

    django的大体结构,django的主要设计思想就是解耦的过程,让每个模块各司其职,只依靠接口进行交互:

    django
        |--urls
        |--views
        |--templates
        |--static
    

    urls记录了路由:

    urlpatterns = [
        path('admin/', admin.site.urls),
        url(r'check_board$', views.check_board),
        url(r'^notice$', views.notice),
    ]
    

      值得一提的是,路由记录的不是一对一的页面对应,一个url对应的可能是一个功能函数,而非页面,具体会不会呈现页面,由views内对应函数的返回值决定。

    views代表视图,能够渲染html的数据:

    @csrf_exempt
    def check_board(request):
        new_list=[]
        result='111'
        if request.is_ajax():
            if request.method == 'POST':
                info = json.loads(request.body.decode()).get('check_board')
                if info:
                    sql = 'select board_id from fpga_info'
                    old_list = select_pc_from_table(sql)
                    save_data = info["value_dict"]
                    print('checkkkkkkkkkkkkkkkk',save_data)
                    for i in range(len(save_data)):
                        if (save_data[i] is None):
                            pass
                        else:
                            new_list.append(save_data[i]['board_id'])
                    if new_list!=[]:
                        diff_a_b=set(old_list).difference(new_list)
                        diff_b_a=set(new_list).difference(old_list)
                        union_df=diff_a_b.union(diff_b_a)
                        result=json.dumps(list(union_df))
                        print(result)
        return HttpResponse(result, content_type="text/javascript")
    

      以此函数为例,其作用是通过ajax与前台js交互,其只负责递交result给js,具体如何处理,并不关心。

    templates是模板,里面是html页面,与C++模板意义上类似,一个html的页面能够装纳views传输的数据。

    static是用于装纳css格式及js文件的,css主要用于影响前台页面的展现效果,js主要用于前台的交互,设计良好能够减少前后台交互,增强体验。

    ---------------------------------------分割线------------------------------------------

    model篇:

    初步去实现了一下model的使用方式,在此稍作记录:

    models增加:

    NightResult.objects.create(**save_data[i])

    models删除:

    save_data={'id'=111,'name'='222'}
    NightResult.object.update(**save_data)

    models修改:

    T=NightResult.objects.filter(id=save_data[i]['id'])
    del save_data[i]['id']
    T.update(**save_data[i])

    models查找:

    temp = NightResult.objects.filter(test_time=date)

    其中NightResult为models.py实际的class,即表名(注意从数据库中导入到models文件后,表名是有区别的),filter类似于查找,test_time为数据表中的列名。

    models字典式查询方式:

    dic={'test_time':'20210125','id__contains':'168'}
    T = NightResult.objects.filter(**dic)

    其中,__contains代表id中包含168的项目,即模糊查询,以下将简单记录几个有代表性的。

    models后缀表意:

    __gt 大于> 
    __gte 大于等于>=

    仅以此实例,其余类似:

    Student.objects.filter(age__lt=10) // 查询年龄小于10岁的学生
    Student.objects.filter(age__lte=10) // 查询年龄小于等于10岁的学生

    __lt 小于<
    __lte 小于等于<=

    __exact 精确等于 like 'aaa'
    __iexact 精确等于 忽略大小写 ilike 'aaa'
    __contains 包含 like '%aaa%'
    __icontains 包含,忽略大小写 ilike '%aaa%',但是对于sqlite来说,contains的作用效果等同于icontains。

    __in 查询包含在某一范围,请不要以为这是x<y<z的类型,其原理类似于x in [y,z]

    __range 此后缀表示在某一范围,及 x<y<z

    datas['test_time__range'] = [dic['date1'], dic['date2']]
    T = NightResult.objects.filter(**datas)

    __isnull 判空

    __startswith 以…开头
    __istartswith 以…开头 忽略大小写
    __endswith 以…结尾
    __iendswith 以…结尾,忽略大小写
    __range 在…范围内

    __year 日期字段的年份
    __month 日期字段的月份
    __day 日期字段的日

    Book.objects.filter(create_time__year=2019, create_time__month=4).all()

    models返回列名:

    T = NightResult.objects.filter(result='pass')
    filed = T[0]._meta.fields
    params = [f for f in filed]
    lis = []
    for i in params:
        lis.append(i.name)

    首先获取查询结果,选择第一项对其fields进行遍历,即可获取列名

    models排序:

    UserData.objects.filter(**dic).order_by('hour') #正序
    UserData.objects.filter(**dic).order_by('-hour')#降序

    models单表聚合:

    页面进行检索时,可能需要数据库提供一定量的已有选项,所以出现了与SQL中group_by类似的用法:

    T = NightResult.objects.values('name_id').distinct()

    暂时没有应用多表的聚合问题,暂不记录。

    下一步去了解ajax的局部刷新来应用于搜索功能。

    对于model查询结果的格式整理:

    values_list('pc_ctrl_ip')=[(,)] values_list('pc_ctrl_ip','status')=[('','')]

    models的查询方式是ORM模型提供的,其具有一定的封装性,如果追求效率,用sql原生语句会更快一些,可是看网上的一些言论说,如果追求优化,那么一开始就不会选择django作为开发工具。汗= =。

    后来我根据实际操作,以我们目前的sql查询语句(单纯的查询某月的测试结果为例),实际测试结果如下:

     嗯....说真的,我也不知道为什么,sql查询就这么一句难道还有优化的可能吗?我没有追溯这个问题产生的原因,基于原代码系统,既然当前models对此系统有益,那自然采纳。

    这里发现了是为什么,这始于django的一中class,queryset,就是查询集,从数据库里获取到对象数据集合.但是有个特点就是它不是直接查询数据的,而是只是定义了一个查询集,在你调用的时候才查询数据库,并且查询同一个查询集后还会自己生成一个缓存,在你以后再次查询同样的查询集会使用缓存的数据,这样节省了查询数据库的资源,有点类似迭代器,因此上面产生这个差异的原因极可能是因为缓存的问题

    后期打算写一篇关于queryset的文章用于记录。

    ----------------------------------------------------------------------------------------------------------

    handlebars.js与pagination.js

    之前探讨了models的使用方式,这次的更新迭代涉及到了前端的一些东西----局部刷新,因为之前使用的是后端映射的方式进行页面刷新,所以这次修改内容较为繁多,要查找的东西自然也多一些,其中还涉及到一些性能问题,可是其实我觉得项目并没有进行商业化而仅仅是对内便捷式使用,所以仍然使用的django,一些帖子说django的性能并不好,这个待证实。

    更新方式主要涉及两个方面,第一使用了“模板语言” handlebars,第二原分页模式不再使用,于是探讨pagination的js可用的js包,奈何能力有限,可见范围内的pagination包全部有大大小小的问题,可是奈何我js能力确实不太强,源码实在懒得看,然后在脚儿网找到了博主自己写的pagination包。

    原生思路:pagination直接通过ajax从后台调用数据调用handlebars模板使网页局部刷新

    现实:可能是我能力问题,脚儿网的分页、翻页等功能一应俱全,就是没有数据调用。

    故四处奔走寻找方式,奔走过程中,突然萌生一个问题,数据量大的情况下,数据到底交给前台处理还是后台处理?起初我只有一股脑丢给前台或者后台的思路,可是一个博主说,一般分页情况下,是前台需求一页的数据,然后通过ajax调用一页的数据。

    好家伙!原来是我愚笨了,然后发现脚儿网的包其实并没有问题,只是需要我们自己去写调用数据的函数而已。

    思路齐全后,开始一步步的走通路---handlebars作用于表格√、pagination封装下的handlebars作用于表格√、表格实现ajax式局部刷新√、与后端models查询数据产生联动并正确显示√

    所有功能基本完善,还没来得及应用先来记录一波,怕自己以后遗漏什么。

    handlebars

    具体包的下载地址在这个超链接中,通过git即可下载,具体语法可以在该官网查询获得。

    很多论坛说handlebars更快一些,因为它会预编译,可是具体快不快其实我并不清楚,我的主要目的还是实现功能,并且利于维护。

    只在这里做简单的说明:

    <script id="xx-template" type="text/x-handlebars-template">
            {% verbatim %}
    {{#each info}}
        <tr class="tr_c_line" align='center' id="tr_c_id" style="background:#F5F5F5" cellspacing="0" cellpadding="0" border="1" data-sortlist="[[0,0],[2,0]]">
            <td class="td">
                <div class="board_div" name='c_edit' contenteditable="false">
                    <select id="board_id{{fields.id}}" style="60px;text-align-last:center;" name="board_id">
                        <option selected> {{fields.board_id}} </option>
                        {{#each ../list.board_list}}
                        <option>{{this}}</option>
                        {{/each}}
                    </select>
                </div>
            </td>
        </tr>
    {{/each}}
        {% endverbatim %}
    </script>

    each可做遍历作用,其中{% verbatim %}{% endverbatim %}在django的联调模式中必须添加,不然会产生冲突而发生错误,vue不是太清楚。

    script中的id适用于后面调用模板所做的准备,因为我们需要确认模板,具体数据如何调用,待我放出data之后,就可以了然,值得一提的是 ../的意思是访问父属性。

    data:

    var dataSource={
            info:[
          {
            fields:
            {           id:
    '123', board_id:'s1', }
          }, {
            fields: {   id:
    '124',   board_id:'s3', }
          } ] list:
        {
          board_list : [
    'm1','m2','m3'] } }

    可能存在错误,我临时修改的数据。结合以下代码食用更佳:

    <tbody id="tbody">
                </tbody>
    var tpl   =  $("#xx-template").html();
    var template = Handlebars.compile(tpl);
    var html = template(dataSource);
    $("#tbody").html(html);

    可以看出dataSource实际上在页面上并没有用到,我们直取的info和list,这是个坑,网上很多代码是直取的dataSource,是有问题的。另外pagination和handlebars都给了我很新奇的一种思路,就是数据存储位置和模板位置未必要一致。这也体现出html灵活的地方。

    综上,主要3个坑点,1、注意django与handlebars的适用性。2、父属性的如何访问。3、dataSource如何访问的。

    补充一个handlebars的华点:

    一般我们拿来js包都是直接使用并没有注意它有什么,这里补充一个:自定义函数

    <script>
    Handlebars.registerHelper("inc", function(value, options) { return parseInt(value) + 1; });
    </script>

    它的功能:

    <td >
         <div name="numid" contenteditable="false">{{inc @index}}</div>
    </td>

    背景:@index可以访问当前each序号,可是它是从0开始,我们需求是它需要+1.可是直接+1是错误操作,于是我们通过inc来进行一个自加操作。

    pagination

    安装包可根据超链接内的git下载。使用方式按照git给的使用方式即可。git内有example是非常好的实例。

    附上我如何与handlebars联动的。

        <div id="aaa" align='center'></div>
    <script>
    item=123
    i=111
    var pagenav1 = xPagination(pagediv, {
        max:7,
        curr:1,
        size:15,
        items:item,
        jump:true,
        showSize:[15,30,i],//回传的数组需要去影响这个showSize与items
        onpagination: function  (page, size) {
            changepage(page,size)
        }
    })
    function changepage(page,size){
            $.ajax({
            url: '/test1' ,
            data: JSON.stringify({'111':'1'}),
            // data: body,
            contentType: "application/json;charset=utf-8",
            traditional: true,
            dataType: 'json',
            type: 'POST',
            async:true,
            success: function (data) {
                console.log(data)
                var dataSource={'info':[]}
                dataSource['list']=data.list
                dataSource.info=JSON.parse(data.info)
                console.log('kkkkkkkkkkkkk',dataSource)
                var tpl   =  $("#xx-template").html();
                var template = Handlebars.compile(tpl);
                var html = template(dataSource);
                $("#tbody").html(html);
             },
            error: function(XMLHttpRequest, textStatus, errorThrown) {
                alert(XMLHttpRequest.status);
                alert(XMLHttpRequest.readyState);
                alert(textStatus);
            },
        });
    }
    </script>

    这段代码已经可以说明大部分问题,这里我还没有涉及到翻页,翻页页码和每页显示多少条的size问题可置于后台处理。

    这次更新可能至此。目前并无什么新需求,后面遇到什么问题可能也是在原博文更新。

    ----------------------------------------------------------------------------------------

    既昨天的思路我开始对目前的代码进行泛化处理,结果第一步就踩坑了,pagination的items我本身是写死的,可是在应用过程中使用的是后台传入的数据大小,是不能够产生作用的

    那我们怎么去应用改变这个items呢?首先补充一个之前我不知道的东西。

    JS执行顺序

    首先我们这里的js为HTML文档嵌入式的应用,而HTML是按照文档流顺序执行的,因此JS作为HTML文档的一部分也是按照文档流顺序执行,而这个顺序是<script>决定,这个顺序不会因为外部JS文件而延期执行。为什么这么说呢,因为<script>内部会产生不一样的预编译顺序。以下实例皆出自此博文:https://www.jb51.net/article/44123.htm

    1.预编译与执行顺序

    <scripttype="text/javascript">
    function Hello() { alert(
    "Hello"); } Hello(); var Hello = function() { alert("Hello World"); } Hello();
    </script>

    运行之后会发现它输出了两次hello world。而并不是hello和hello world。

    这是因为JS并非完全顺序解释执行,而是在解释之前对JS进行一次预编译,在预编译过程中,会把定义式的函数优先执行,也会把所有的var变量创建,默认值为undefined,以提高程序的执行效率。

    由此,预编译后的代码:

    <scripttype="text/javascript">        
    varHello = function() {           
    alert("Hello");        
    }       
    Hello = function() { 
               alert("Hello World");  
          }      
    Hello();     
    Hello();  
    </script>

    为什么会输出两次hello world可见一斑。

    如何得到我们预想的输出呢?

    <scripttype="text/javascript">      
    functionHello() {        
    alert("Hello");       
    }        
    Hello();  
    </script>   
    <scripttype="text/javascript">   
    functionHello() {          
    alert("Hello World");     
    }       
    Hello();  
    </script>

    通过<script>将程序分成两段,那样js就不会将其放到一起进行处理。

    另外,变量赋值是在执行期而不是预编译期。

    alert(a);                            // 返回值undefined
    var a =1;
    alert(a);                            // 返回值1

    而函数定义和调用稍有不同。

    f();                                 // 调用函数,返回值1
    function f(){
        alert(1);
    }
    f();                                 // 调用函数,返回语法错误
    var f = function(){
        alert(1);
    }

    其差异性在于,前者是定义,而后者是赋值,赋值只会产生在调用阶段。

    <script type="text/javascript">
    /*在预编译过程中func是window环境下的活动对象中的一个属性,值是一个函数,覆盖了undefined值*/
    alert(func); //function func(){alert("hello!")}
    var func = "this is a variable"
    function func(){
    alert("hello!")
    }
    /*在执行过程中遇到了var重新赋值为"this is a variable"*/
    alert(func);  //this is a variable
    </script>
    <script type="text/javascript"> 
    var name = "feng"; function func()
    { 
    /*首先,在func环境内先把name赋值为undefined,然后在执行过程中先寻找func环境下的活动对象的name属性,此时之前已经预编译值为undefined,所以输出是undefined,而不是feng*/ 
    alert(name);  //undefined var name = "JSF"; 
    alert(name);  //JSF 
    }
    func(); 
    alert(name); 
    //feng
    </script>

    从上面也不难看出,JS在同一<script>下会产生定义和赋值上的问题,但是在不同的<script>中则不会产生这种问题,由此可见JS是按代码块执行

    2.借助时间改变JS预编译执行顺序

    <script>
    // JavaScript代码块1
    window.onload = function(){        // 页面初始化事件处理函数
        alert(a);
        f();
    }
    </script>
    <script>
    // JavaScript代码块2
    var a =1;
    function f(){
        alert(1);
    }
    </script>

    一般页面初始化完毕之后才允许执行JS代码,避免网速对JS执行的影响,也避免了HTML文档流对JS执行的限制。

    如果页面存在多个windows.onload事件处理函数,那么只有最后一个才有效,可以将所有脚本或调用函数都放在同一个onload时间中进行处理。

    window.onload = function(){
        f1();
        f2();
        f3();
    }

    简化之后这些讲解还是有点多。不过还是值得的。到这问题其实已经解决了。

    两个<script>第一个定义items第二个对pagination进行初始化,但是问题在于,需要查两次。

    第一个代码块获取items需要后台查一次,第二次初始化需要查第二次。

    第二次为什么产生呢?因为pagination的onpagination函数一加载页面会自动调用,即使是第一页,而且我们通过pagination调用handlebars避免不了查第二次。

    那如果查的第一次就存下数据呢?

    这违背了我们思路的初衷,首先,你不知道页面的size,也就是当前页面能存储多少条数据,那么你就需要把所有数据留在页面,但是,我们的思路是看一页取一页。

    查过官方的pagination,也是事先规定了pagination的items和页数之类,限于水平目前还未找到优化的可能。

    ------------------------------------------------------------------------------------------------

    就昨天的实践内容,打算实装的时候发现一个问题,我搜索,局部刷新,页面不刷新那么我第一次后台查询就不会调用,当然我们可以搜索的时候自动调用这一个。

    可是当时我发现我当时实践过程中的一个华点。我修改了pagenav1的options中items的属性,修改成功了为什么没生效?其实生效了,不过它需要翻页刷新状态,这可能是这个JS包设计上的缺陷,不过对于我们目前的内部使用来说是可以使用的,后期如果能力允许可以进行手动修改。

    另外,虽然翻页能够刷新页码数,可是条数其实是不变的。

     如图,两个300很突兀,2*15显然是30才对,这部分可以在onpagination里面对页面标签进行修改,问题不大。

    -----------------------------------------------------------------------------------------------

    JS的碎片整理:

    文本框: innerHTML
    select: val()
    上下table列无法对齐的情况:设置table style: style="table-layout: fixed;",这样表格的内容将不会影响td的长度

  • 相关阅读:
    Gradview读取Excel表并插入数据库
    键盘上每个键作用!!! (史上最全的)­
    经典SQL语句大全
    [转帖] 一个老乞丐的一句话,震惊全中国人!
    GridView控件实现自定义数字、时间、货币字符串格式
    .net连接数据库相关
    论坛Email验正的正则表达式升级
    自定义DBHelper类
    在线编辑器CuteEditor使用方法
    asp.net中验证码的生成
  • 原文地址:https://www.cnblogs.com/threeidiots/p/14139306.html
Copyright © 2020-2023  润新知