Python Django:在视图中,最好是为对象添加属性还是创建数据字典
在这种情况下,我的模型并不重要,我认为这是一个基本的
Python问题.
假设我有一个项目的查询集,我想计算每个要在模板中显示的东西. 在我看来,我可以创建一个对象列表,对于每个对象,我可以在该对象上设置一个属性进行计算,然后我可以在模板中显示它.或者我可以创建一个字典列表,只获取我需要在每个字典中显示的字段以及计算字段.对于性能和一般实践来说哪个更好? 一个过于简化的示例,为了清晰起见(我知道我可以从模板中调用getAge(),我真正计算的是更复杂的,对于性能,我想在视图代码中进行计算): models.py: class Person(models.Model): first_name = ... last_name = ... date_of_birth = ... . . . def getAge(self): return ... # return the calculated years since date_of_birth views.py: def method1_object_property(request): people = Person.objects.all() for p in people: p.age = p.getAge() return render_to_response('template.htm',{'people': people}) def method2_dictionary(request): people = Person.objects.all() data = list() for p in people: row = dict() row['first_name'] = p.first_name row['last_name'] = p.last_name row['age'] = p.getAge() data.append(row) return render_to_response('template.htm',{'people': data}) template.htm: <ul> {% for p in people %} {{ p.first_name }} {{ p.last_name }} (Age: {{ p.age }}) {% endfor %} </ul> 到目前为止,这两种方法都可以正常工作,我只是好奇首选方法是什么以及为什么.是否存在使用对象点属性方法(object.new_field =’some_detail’)将新字段动态分配给内存中现有对象的性能问题? 更新: 是的,我知道在我的例子中我可以从模板调用getAge(),是的,这是方法的不正确的命名标准,应该是带有下划线的小写.我认为我的例子太简单了,而且让我真正想知道的事情蒙上阴影. 将信息添加到我想要在视图中显示的对象的最佳方法是什么,该视图不是模型层的一部分.假设我得到一个Person对象的QuerySet,并想要计算他们在过去30,60和90天登录我网站的次数.我想动态为每个Person对象创建三个“属性”.我可以在视图中设置它 for p in people: p.last_30 = Login.objects.filter(person=p,login_date__gt=date.today()-timedelta(days=30)) p.last_60 = Login.objects.filter(person=p,login_date__gt=date.today()-timedelta(days=60)) p.last_90 = Login.objects.filter(person=p,login_date__gt=date.today()-timedelta(days=90)) 然后在我的模板中,我可以显示那些“属性”.我只是想确保我没有违反某些Python标准或欺骗系统.或者,我可以将这些其他查找存储在字典中,其中对象在一个键/对中,并且各个细节在单独的键中.在视图中这是一个更多的工作,但我很好奇是否更好的性能或标准的合规性这样做? 对不起,如果我的原始问题不够清楚,或者我的例子增加了混乱. 解决方法
绝对方法1.
方法2毫无意义,您可以直接在模板中迭代查询集,无需在视图中构建中间的“词典列表”.例如,你可以这样做: def method2_dictionary(request): people = Person.objects.all() return render_to_response('template.htm',{'people': people}) 在您的模板中: {% for p in people %} {{ p.first_name }} etc {% endfor %} 回到方法1 …… 这个:p.age = p.getAge()也没有意义,你可以直接调用模板中的方法{{p.getAge}}(只要你的方法不带参数),请看这里的文档: 请注意,在Python中,我们通常更喜欢使用“带下划线的小写”作为方法名称,例如def get_age(self)和{{p.get_age}} 如果你的get_age方法没有side-effects并且没有参数你可能想让它成为一个属性,这是Python的方法,你可以访问没有括号的getter方法. 在这种情况下,将它命名为年龄是有意义的: @property def age(self): return ... # return the calculated years since date_of_birth 并在您的模板中: {% for p in people %} {{ p.first_name }} {{ p.age }} etc {% endfor %} 有关Python属性的更多信息,请参见此处: 在这个SO问题中的更多信息: UPDATE 参考您更新的问题…作为样式问题,我仍然会在模型上创建这些(last_30等)方法,而不是在视图代码中的每个模型实例上添加ad hoc属性. 从性能的角度来看,在大多数现实世界中,方法查找与字典等的内存,处理时间等的差异是微不足道的……到目前为止,这种代码中最大的性能考虑通常是数据库查询的数量. 如果您知道要为查询集中的每个项目执行额外的查询(或三个),那么值得寻找在一个或多个大查询中获取所有内容的方法. 在某些情况下,您可以使用annotate()方法: (我认为这不可能在你的例子中) 在上面的特定代码中,您只需查询90天(最早的间隔),您可以在Python中过滤60天和30天的集,而无需再次查询数据库. 但是,对于人员查询集中的每个项目,仍然会进行一次额外查询.最好为人员的所有(或任何子集)的Login对象执行一个大查询.由于登录时Person有一个外键关系,我们可以在查询Login模型时使用 def method3(request): logins = Login.objects.filter( person__in=Person.objects.all(),login_date__gt=date.today() - timedelta(days=90) ).order_by('person','login_date').select_related() return render_to_response('template.htm',{'logins': logins}) 注意,如果你真的在做Person.objects.all(),你就不需要上面的person__in过滤器,只要你想以某种方式过滤Person集. 现在我们在一个大查询中获得了所有数据,我们可以在python端执行我们需要的操作来显示数据.例如,在模板中我们可以使用 {% regroup logins by person as people %} {% for person in people %} {% with person.grouper as p %} {{ p.first_name }} {% for login in person.list %} {{ login.login_date }} {% endfor %} {% endwith %} {% endfor %} 你可以更进一步,为登录日期范围写一个自定义标签…我不会在这里详细说明,但在你的模板中它可能看起来像: {% regroup logins by person as people %} {% for person in people %} {% with person.grouper as p %} {{ p.first_name }} {% logins_since person.list 60 as last_60_days %} {% logins_since person.list 30 as last_30_days %} {% for login in last_30_days %} {{ login.login_date }} {% endfor %} {% for login in last_60_days %} {{ login.login_date }} {% endfor %} {% endwith %} {% endfor %} (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |