django模板遍历如何控制次数?

导读:很多朋友问到关于django模板遍历如何控制次数的相关问题,本文首席CTO笔记就来为大家做个详细解答,供大家参考,希望对大家有所帮助!一起来看看吧!

如何有效的遍历django的QuerySet

(post),后台对post的参数进行解析,通过models模型查询MySQL,将数据结构进行加工,返回到前台页面进行展示。由于对django中

QuerySet特性的不熟悉,所以测试过程中发现了很多问题。

开始的阶段没有遇到什么问题,我们举例,在models有一张员工表

employee,对应的表结构中,postion列表示员工职位,前台post过来的参数赋给position,加上入职时间、离职时间,查询操作通过

models.filter(position=params)完成,获取的员工信息内容由QuerySet和当前展示页与每页展示的记录数进行简单的计

算,返回给前台页面进行渲染展示。编码如下:

1 def get_employees(position, start, end):

2 return employee.objects.filter(alert_time__lt=end,alert_time__gt=start).filter(position__in=position)

3

4

5 @login_required

6 def show(request):

7 if not validate(request):

8 return render_to_response(\'none.html\',

9 context_instance=RequestContext(request, \'msg\':\'params error\')

10 )

11

12 position = request.REQUEST.get(\'position\')

13 time_range = request.REQUEST.get(\'time\')

14 start, end = time_range[0], time_range[1]

15

16 num_per_page, page_num = get_num(request)

17 all_employees = get_employees(position, start, end)

18 # 根据当前页与每页展示的记录数,取到正确的记录

19 employees = employees_events[(page_num-1)*num_per_page:page_num*num_per_page]

20

21 return render_to_response(\'show_employees.html\',

22 context_instance=RequestContext(

23 request,

24 \'employees\': employees,

25 \'num_per_page\': num_per_page,

26 \'page_num\':page_num,

27 \'page_options\' : [50, 100, 200]

28 )

29 )

运行之后可以正确的对所查询的员工信息进行展示,并且查询速度很快。

employee表中存放着不同职位的员工信息,不同类型的详细内容也不相同,假设employees有一列名为infomation,存储的是员工的详

细信息,infomation = {\'age\': 33, \'gender\': \'male\', \'nationality\': \'German\',

\'degree\': \'doctor\', \'motto\': \'just do

it\'},现在的需求是要展示出分类更细的员工信息,前台页面除了post职位、入职离职时间外,还会对infomation中的内容进行筛选,这里以查

询中国籍的设计师为例,在之前的代码基础上,需要做一些修改。员工信息表employee存放于MySQL中,而MySQL为ORM数据库,它并未提供类

似mongodb一样更为强大的聚合函数,所以这里不能通过objects提供的方法进行filter,一次性将所需的数据获取出来,那么需要对type

进行过滤后的数据,进行二次遍历,通过information来确定当前记录是否需要返回展示,在展示过程中,需要根据num_per_page和

page_num计算出需要展示数据起始以及终止位置。

1 def get_employees(position, start, end):

2 return employee.objects.filter(alert_time__lt=end,alert_time__gt=start).filter(position__in=position)

3

4

5 def filter_with_nation(all_employees, nationality, num_per_page, page_num):

6 result = []

7

8 pos = (page_num-1)*num_per_page

9 cnt = 0

10 start = False

11 for employee in all_employees:

12 info = json.loads(employee.information)

13 if info.nationality != nationality:

14 continue

15

16 # 获取的数据可能并不是首页,所以需要先跳过前n-1页

17 if cnt == pos:

18 if start:

19 break

20 cnt = 0

21 pos = num_per_page

22 start = True

23

24 if start:

25 result.append(employee)

26

27 return employee

28

29

30 @login_required

31 def show(request):

32 if not validate(request):

33 return render_to_response(\'none.html\',

34 context_instance=RequestContext(request, \'msg\':\'params error\')

35 )

36

37 position = request.REQUEST.get(\'position\')

38 time_range = request.REQUEST.get(\'time\')

39 start, end = time_range[0], time_range[1]

40

41 num_per_page, page_num = get_num(request)

42 all_employees = get_employees(position, start, end)

43

44 nationality = request.REQUEST.get(\'nationality\')

45

46 employees = filter_with_nation(all_employees, num_per_page, page_num)

47

48 return render_to_response(\'show_employees.html\',

49 context_instance=RequestContext(

50 request,

51 \'employees\': employees,

52 \'num_per_page\': num_per_page,

53 \'page_num\':page_num,

54 \'page_options\' : [50, 100, 200]

55 )

56 )

当编码完成之后,在数据employee表数据很小的情况下测试并未发现问

题,而当数据量非常大,并且查询的数据很少时,代码运行非常耗时。我们设想,这是一家规模很大的跨国公司,同时人员的流动量也很大,所以employee

表的数据量很庞大,而这里一些来自于小国家的员工并不多,比如需要查询国籍为梵蒂冈的员工时,前台页面进入了无尽的等待状态。同时,监控进程的内存信息,

发现进程的内存一直在增长。毫无疑问,问题出现在filter_with_nation这个函数中,这里逐条遍历了employee中的数据,并且对每条

数据进行了解析,这并不是高效的做法。

在网上查阅了相关资料,了解到:

1 Django的queryset是惰性的,使用filter语句进行查询,实际上并没有运行任何的要真正从数据库获得数据

2 只要你查询的时候才真正的操作数据库。会导致执行查询的操作有:对QuerySet进行遍历queryset,切片,序列化,对 QuerySet 应用 list()、len()方法,还有if语句

3 当第一次进入循环并且对QuerySet进行遍历时,Django从数据库中获取数据,在它返回任何可遍历的数据之前,会在内存中为每一条数据创建实例,而这有可能会导致内存溢出。

上面的原来很好的解释了代码所造成的现象。那么如何进行优化是个问题,网上有

说到当QuerySet非常巨大时,为避免将它们一次装入内存,可以使用迭代器iterator()来处理,但对上面的代码进行修改,遍历时使用

employee.iterator(),而结果和之前一样,内存持续增长,前台页面等待,对此的解释是:using iterator()

will save you some memory by not storing the result of the cache

internally (though not necessarily on PostgreSQL!); but will still

retrieve the whole objects from the database。

这里我们知道不能一次性对QuerySet中所有的记录进行遍历,那么只能对

QuerySet进行切片,每次取一个chunk_size的大小,遍历这部分数据,然后进行累加,当达到需要的数目时,返回满足的对象列表,这里修改下

filter_with_nation函数:

1 def filter_with_nation(all_employees, nationality, num_per_page, page_num):

2 result = []

3

4 pos = (page_num-1)*num_per_page

5 cnt = 0

6 start_pos = 0

7 start = False

8 while True:

9 employees = all_employees[start_pos:start_pos+num_per_page]

10 start_pos += num_per_page

11

12 for employee in employees:

13 info = json.loads(employee.infomation)

14 if info.nationality != nationality:

15 continue

16

17 if cnt == pos:

18 if start:

19 break

20 cnt = 0

21 pos = num_per_page

22 start = True

23

24 if start:

25 result.append(opt)

26

27 cnt += 1

28

29 if cnt == num_per_page or not events:

30 break

31

32 return result

运行上述代码时,查询的速度更快,内存也没有明显的增长,得到效果不错的优

化。这篇文章初衷在于记录自己对django中queryset的理解和使用,而对于文中的例子,其实正常业务中,如果需要记录员工详细的信息,最好对

employee表进行扩充,或者建立一个字表,存放详细信息,而不是将所有信息存放入一个字段中,避免在查询时的二次解析。

django模板遍历如何控制次数?  第1张

django模板循环5次

1、从后台传数据到html的时候就只传需要显示的页数(比如,以一个列表[1,2,3,4,.....]),然后在html for循环

2、把全部页数都传到前台,列出来,然后用js控制哪些显示,哪些隐藏。

怎样在django 模板中只显示前n条记录

django在循环中有一个forloop的变量, 你查一下, 应该对你有用, 判断当前已经遍历了多少条, 然后退出循环就可以了, 不过模板中不支持break和continue语法, 我暂时只能想到这些。

结语:以上就是首席CTO笔记为大家整理的关于django模板遍历如何控制次数的全部内容了,感谢您花时间阅读本站内容,希望对您有所帮助,更多关于django模板遍历如何控制次数的相关内容别忘了在本站进行查找喔。

以上内容为新媒号(sinv.com.cn)为大家提供!新媒号,坚持更新大家所需的互联网后端知识。希望您喜欢!

版权申明:新媒号所有作品(图文、音视频)均由用户自行上传分享,仅供网友学习交流,不声明或保证其内容的正确性,如发现本站有涉嫌抄袭侵权/违法违规的内容。请发送邮件至 k2#88.com(替换@) 举报,一经查实,本站将立刻删除。

(0)
上一篇 2023-09-23 13:18
下一篇 2023-09-23

相关推荐

发表回复

登录后才能评论