一些实习经验总结(二)

今天差不多把项目做完了,还要优化美化我也不知道从什么方向下手,看到时候给什么建议吧。那么接下来就总结一下关于项目echarts构建时大概流程以及一些问题吧。

一、8月2日

上周三,我接到任务,要求实现子任务添加、导入导出、以及迁移的功能,同时完善一下参数和描述。我本来的想法自然是依旧利用layui表格,所以我先花了点时间完善了数据库,把该加的参数啥的都加上了。然后就是用django-import-export组件实现导入导出功能,我一开始搜到的资料比较浅显,我就以为只要pip安装库,再修改一下admin文件把class(admin.ModelAdmin):改成class(ImportExportModelAdmin):就好了,事实上我修改后的确搞出了导入导出按钮,点进去后也有相应的页面,我便以为成功了,就进入了下一个任务。

至于我弃用layui而改为echarts的原因,主要有两点,一是我仔细思考了下,觉得用layui的树形表格实在是不好实现迁移啥的功能,二是说实话我不太喜欢layui的树形表格,我觉得首先他没有很好的体现是层级和树的关系,其次他不怎么美观。所以我就开始搜如何实现树形图,一看echarts觉得这深合我心,于是乎当机立断——改用echarts!这天我也没针对echarts做很多事,只是大概搜了下资料,把echarts引入,实现了一个固定数据的树形图,这里提一下echarts官网下载所需文件可以直接定制,主题也能定制,实在方便的很,唯独搜索api以及参数的时候总感觉不大舒适。

二、8月3日

       时间来到周四,首先我先把echarts的树形图数据关联到数据库数据,这点的实现就要靠前后端传递了,我是现在view视图函数中调用数据库数据并用递归的方式写到了json文件中(由于我是以parent外键与自身连接实现的树结构,所以本身是不能以echarts树形图所需的children格式数据提供的),再在前端页面中获取json文件数据就可以了,这样就成功实现了数据到树形图的可视化

 下一步就是其有关操作,操作无非也就是四个:增、删、改、迁移。但要怎么做出这四个操作呢,我本意是又搞几个按钮,但恰好查资料时我找到了个例子,它是通过鼠标右键点击节点时弹出菜单来实现的,我自然是欣然采纳了。是很好写的,我只需要写一个跳转到django后台自带的change页面就行了,django自带的这个页面的url有个相关的数据的id值,所以可以跳转到对应的编辑页面,然后我本以为增加也可以如法炮制,但django自带的add页面显然是并没有带id值的(不可能为每个元素搞个增加页面吧),那么也想要以这种方式实现的话只能够说在跳转到页面后自动填写好“上级任务”这一栏,不然还得手动填写的话,增加子节点就显得比较鸡肋,但要实现自动填写我查了半天,又只找到通过在url里写值,再在html中获取的方法,本来是很美好的,但问题就在于django自带的add页面我不知道怎么修改其源码,也完全找不到这一先例,无奈之下,我只能选择另一个更痛苦的方法——自己写一个add页面,当然,为了方便和美观,我最后还是没有写一个页面,只是做了个弹窗,效果总体来说还是ok的,通过表单获取用户填写的数据然后用ajax传给后端,后端相应根据传过来的数据来增加子节点,再刷新页面,就成功实现了“增加子节点”的功能。

大致流程就是这么简单,但实现起来还是有不少问题,首先的问题是由于我是用弹出菜单的方式实现操作,点击弹出的ul中不同li,通过工厂里查看绑定方法来实现点击后的不同操作,但由于我绑定的不同方法其实类似于基础的html,我无法获取到这个操作是由哪个节点发起的,echarts本身的myChart.on("click", function(params) 方法就是用params参数来获取,但我自己写的方法里并没有这个参数啊,我的解决方法是设置一个全局变量,在右键呼出菜单的方法里用全局变量把params参数存起来,然后在自己写的方法里就可以获得这个参数了。下一个问题就是有关Ajax传递数据的,由于我的各个操作都需要传递数据给后端,我自然要分辨这到底是对应哪个操作,所以我在

            fetch("/app/index/", {
                method: "POST",
                headers: {
                    "Content-Type": "application/json",
                    "Operate-Type":"Create",
                },
                body: JSON.stringify(taskData)
            })
                .then(response => response.json())
                .then(data => {
                    // 数据成功保存后,刷新页面
                    location.reload();
                });

这段代码的headers中加入了一个自定义的“Operate-Type”,并且想在后端通过判断这个参数来决定是什么操作,但不出意外的报错了(我不记得错误叫啥了),又是痛苦的一番检查和查找,最后发现在后端判断的时候不能用“Operate-Type”,Ajax传递时会自动把它变成“HTTP_OPERATE_TYPE”,也就是全部大写,在前面加HTTP,以及所有-变成_,修正之后总算坎坷地实现了功能,实现了增加,删除自然也好说,一样地传递数据给后端让后端在数据库里删除就可以了。这天差不多做到这里,接下来就是最难的——迁移。

三、8月4日

本来这天我是打算开始做迁移功能的,但师傅让我先把项目用git上传,没办法,我只能又开始研究git,作为一个只在本地写过一些小项目的人来说用git上传可谓新鲜体验,也是痛苦体验,看着诸如 error: src refspec xxx does not match any / error: failed to push some refs to的错误,我只能查来查去,配置ssh啦,看这个命令到底是什么意思啦,最后还是坎坷地上传成功,这里提醒一下,网上很多攻略上传用的是git push -u origin master,而这里的master其实是你仓库的分支名称,而且现在主分支一般也不叫master了我就被这个坑了好久,还有一开始以为这个git bash用不能够粘贴,所有代码都是自己手敲,后面一搜才知道可以用shift+insert来粘贴。不管怎么说,上传最后成功了。

接下来的问题就是迁移,前面也说了,我是希望通过点击“迁移节点”,然后在用flag控制下点击事件,让之后点击节点不是展开折叠而是传递数据,但这又生成另一个问题,为了体现点击后与原先的不同,我势必要对图进行重新渲染,但重新渲染又会导致各节点的展开状态变回初始,这对功能的实现是致命的,所以我必须想办法使得重新渲染后节点展开状态保持不变。我本来以为这是件很简单的事,只需要获取每个节点的展开状态记录下来,重新渲染时再加上去不就行了吗,但该死的echarts居然没给节点加这个参数,唯一的collapsed的只是用来控制节点的初始展开状态的,再读取也没意义,无奈之下,我只能手动给每个data加上一个“isExpanded”参数,然后在让其在每次点击事件后都变化为取反值,这样我就实现了存储各节点展开状态,以及这里记录一下获取根节点的方法:myChart.getOption().series[0].data[0],不过事先存储好后端传过来的data直接用data找根节点好像也行,我暂且没注意二者有什么区别,那么总的来说,这样我就实现了重新渲染后节点展开不变,接下来就是同样的套路,传递数据给后端,然后改变一下parent,再重新写一下数据就可以了。

这里再写一下另一个问题:echarts重新渲染时,option中没重写的值他会保留,而不是完全更新,比方说,你在前面渲染时写的option里面包含了itemstyle,之后再重新渲染时假如option中没有写itemstyle,那么就会保留之前的itemstyle。

其实这天我并没有实现迁移功能,因为遇到了不知道如何获取根节点的问题,究其原因还是对echarts这个东西不够熟悉,也没找什么教程直接就开始用了,于是这里那里的忙的焦头烂额,再加上周五,我便暂时搁置,等到下周一才解决。

四、8月7日

书接上回,我满心欢喜地把迁移功能写好后,又遇到了一个新问题,就是用户权限的问题,这一点我在第一篇文章中写了,这里就不再赘述。反正这天差不多做了迁移这两件事,同时我还注意到了导入导出的问题,但那是明天的事了。

五、8月8日

导入导出

1.导出

我优先解决的自然是导出问题,设置主键很好解决,加一个import_id_fields = 即可解决,但设置列名为中文着实费了我一番功夫,网上的代码大多没解释各个参数到底是什么意思,我只好试来试去,揣摩代码功能,最后是用fields.Field重新设置各参数才实现。而导出最麻烦的还是我加了options字段的参数的对应,如何把实际值转化为显示值,幸好,网上还有相关问题,我也是在重写export方法后成功解决。对了,还有关联外键的问题,这就得使用我们的widget库了,使用widget=ForeignKeyWidget关联到外键,就可以设置其字段,比如说widget=ForeignKeyWidget(job_detail, 'JOB_NAME'),这样设置后,parent就不会显示原来的id值,而是显示相应的JOB_NAME值了,那么导出的问题大致解决,接下来就是更棘手的导入问题了。

2.导入

本来我以为设置好导出后,导入应该就不用管了,模仿导出的文件格式再导入就行了嘛,不过事实并非如此,还有两个很大的问题存在——一是由于我的模型类中有自关联外键parent的属性,导入时,django-import-export的逻辑又是先检查数据,看数据所关联的外键在数据库中是否存在,这就造成了一个很致命的问题,我导入时显然parent对象还不存在,毕竟其还在我导入的文件中嘛,网上也完全没有这样的问题先例(难道大家都没试过导入有自关联外键的类吗),我只好请教师傅,他的建议是要我重写保存的save方法,而我听得云里雾里,没太明白是个什么思路,回过头只好凭借自己的揣测确定一个大概思路——重写resource文件中的before_import_row方法,让其在识别parent时,如果在数据库中找不到,那么就自己添加一个,同时再重写model文件中的save方法,保存时先判断数据库中有没有与其name相同的对象,如果有,那么就不新创建,而是更新其相关值,这个是否更新就是由save方法中的force_update参数控制的,如果为TRUE就只更新,这样一来,虽然好像导致了无法创建重名对象,不过既然我在导入导出时已经将name作为主键,好像也没什么大影响,第一个问题圆满解决。

二是带options字段对象的导入问题,前面也说了,我解决了其导出问题,可导入问题又把我难住了,我本想像导出一样重写一下export方法,于是我跟着ChatGPT的指引开始重写(网上完全找不到带options字段对象的导入问题),然而ChatGPT的指引真是让我吐血,我写入代码后报错,询问他为什么报错,他就开始“非常抱歉,我前面回答错了”,然后啪啪又给我一段代码,我欣然写下,可依旧报错,我又去问他为什么,他依然“非常抱歉,我前面回答错了”,然后把跟第一遍一样的代码又给我,唉……………………这里详细展开说说我要重写的import_data方法,它里面的dataset参数即是导入文件的数据,但他是dataset类型,我完全不知道该如何修改其中的值,本来新建一个newdataset对象来逐行更新保存dataset的row,最后再传递newdataset给原本的import_data 方法,想法很美好,可现实是残酷的,dataset虽然是dataset类的对象,但他又不同于简单的dataset,当我传递新的newdataset时,before_import_row读取到的row参数就会是一个list类型,但原本的dataset传递的则不是,于是我又想能不能遍历dataset的row时修改row,可惜这里的row是元组类型,修改不了。没办法,我只能又琢磨别的方法,最后还是重写了before_import_row方法,在这里做判断,将导入数据中的显示值替换为options中的实际值,终于成功解决!!!

之后还有一些有关echarts样式的问题,虽说不是什么大问题,但真做起来也是要花时间的,下次再说吧

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值