2008-08-03 44 views
45

Django视图指向一个函数,如果您只想更改某些功能,则这可能是一个问题。是的,我可以有百万个关键字参数,如果函数中有更多的语句,但我更多地考虑面向对象的方法。Django中的类视图

例如,我有一个显示用户的页面。该页面与显示组的页面非常相似,但与仅使用其他数据模型不太相似。组也有成员等...

一种方法是指向视图的类方法,然后扩展该类。有没有人尝试过这种方法或有任何其他想法?

回答

41

我创建并使用了我自己的通用视图类,定义了__call__,因此该类的一个实例是可调用的。我很喜欢;虽然Django的泛型视图允许通过关键字参数进行一些定制,但是OO泛型视图(如果它们的行为被拆分成多个单独的方法)可以通过子类化进行更细粒度的自定义,这使我可以更少地重复自己。 (我厌倦了随时重写相同的创建/更新视图逻辑,因为我需要调整Django的通用视图不允许的东西)。

我已经在djangosnippets.org上发布了一些代码。

我看到的唯一真正的缺点是内部方法调用的泛滥,这可能会影响性能。我认为这不是一个大问题; Python代码执行很少会成为Web应用程序中的性能瓶颈。

UPDATE:Django自己的generic views现在是基于类的。

UPDATE:FWIW,自从写了这个答案以来,我改变了对基于类的观点的看法。在一些项目中广泛使用它们之后,我觉得它们倾向于编写令人满意的DRY代码,但以后很难阅读和维护,因为功能遍布于许多不同的地方,并且子类是如此依赖的关于超类和mixin的每个实现细节。我现在觉得TemplateResponse和查看装饰器是分解视图代码的更好的答案。

+0

Python执行不是瓶颈,但可能会影响网站的可扩展性和整体性能。我很高兴memcache存在! – StefanNch 2012-12-23 12:06:46

2

听起来像你想要结合不应该组合的东西。如果您需要在视图中执行不同的处理,具体取决于它是否是您想要查看的用户或组对象,那么您应该使用两种不同的视图函数。

另一方面,可以有你想从对象中提取出来的常见习语_详细类型视图......也许你可以使用装饰器或只是辅助函数?

-Dan

9

如果你只是从模型显示数据,为什么不使用Django Generic Views?它们旨在让您轻松展示模型中的数据,而无需编写自己的视图和将URL参数映射到视图,获取数据,处理边缘情况,呈现输出等内容。

2

除非您想做一些有点复杂的东西,使用通用视图是要走的路。它们比它们的名字所暗示的功能强大得多,如果你只是显示模型数据,通用视图将完成这项工作。

1

如果您想在页面之间共享通用功能,我建议您查看自定义标签。他们相当于easy to create,而且非常强大。

另外,templates can extend from other templates。这使您可以拥有一个基本模板来设置页面的布局,并在填充空白的其他模板之间共享该模板。您可以将模板嵌套到任何深度;允许您在单独的一组相关页面上指定布局。

+0

我不认为在模板中放置太多的逻辑是一个好主意。 – 2010-09-17 11:48:39

3

你总是可以创建一个类,覆盖__call__功能,然后将URL文件指向类的一个实例。您可以查看FormWizard课程,了解如何完成这项工作。

+0

标记处理器吃了你的\ _ \ _'s。使用\\ _隐藏标记。类\ _ \ _ call \ _ \ _方法就是所谓的。问题是要确保urls.py具有可用的类的实例。 它使你的urls.py稍微复杂一些。 – 2008-09-17 02:07:54

1

通用视图通常是要走的路,但最终你可以自由地处理URL但不管你想要的。 FormWizard以基于类的方式执行某些操作,就像使用RESTful API的某些应用程序一样。

基本上用一个URL给你一堆变量,并提供一个可调用的地方,你提供的调用完全取决于你 - 标准的方法是提供一个函数 - 但是最终Django对你的内容没有限制做。

我的确同意,如何做到这一点的更多的例子会很好,FormWizard可能是开始的地方。

13

我需要使用基于类的视图,但我希望能够在我的URLconf中使用该类的全名,而不必在使用它之前实例化视图类。什么帮助我是一个令人惊讶的简单元类:

class CallableViewClass(type): 
    def __call__(cls, *args, **kwargs): 
     if args and isinstance(args[0], HttpRequest): 
      instance = super(CallableViewClass, cls).__call__() 
      return instance.__call__(*args, **kwargs) 
     else: 
      instance = super(CallableViewClass, cls).__call__(*args, **kwargs) 
      return instance 


class View(object): 
    __metaclass__ = CallableViewClass 

    def __call__(self, request, *args, **kwargs): 
     if hasattr(self, request.method): 
      handler = getattr(self, request.method) 
      if hasattr(handler, '__call__'): 
       return handler(request, *args, **kwargs) 
     return HttpResponseBadRequest('Method Not Allowed', status=405) 

我现在既可以实例化视图类和使用情况的视图功能,或者我可以简单地指向我的URL配置上我的课,并有元类实例化(和调用)对我来说是视图类。这可以通过检查__call__的第一个参数来工作 - 如果它是HttpRequest,它必须是一个实际的HTTP请求,因为使用HttpRequest实例尝试实例化一个视图类是无稽之谈。

class MyView(View): 
    def __init__(self, arg=None): 
     self.arg = arg 
    def GET(request): 
     return HttpResponse(self.arg or 'no args provided') 

@login_required 
class MyOtherView(View): 
    def POST(request): 
     pass 

# And all the following work as expected. 
urlpatterns = patterns('' 
    url(r'^myview1$', 'myapp.views.MyView', name='myview1'), 
    url(r'^myview2$', myapp.views.MyView, name='myview2'), 
    url(r'^myview3$', myapp.views.MyView('foobar'), name='myview3'), 
    url(r'^myotherview$', 'myapp.views.MyOtherView', name='otherview'), 
) 

(我张贴此片段在http://djangosnippets.org/snippets/2041/

+1

完全真棒 – Anentropic 2010-10-27 19:05:39

1

您可以使用Django的通用视图。你可以很容易地实现所需的功能彻底的Django通用视图