记录一个关键问题,导出的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的长度