Django视图指向一个函数,如果您只想更改一些功能,这可能是一个问题。是的,我可以拥有数百万个关键字参数,甚至更多if函数中的语句,但我更多地考虑面向对象的方法。
例如,我有一个显示用户的页面。此页面与显示组的页面非常相似,但它仍然不像仅使用其他数据模型。集团也有会员等...
一种方法是将视图指向类方法,然后扩展该类。有没有人试过这种方法或有任何其他想法?
答案 0 :(得分:42)
我已经创建并使用了我自己的通用视图类,定义了 __call__
,因此该类的实例是可调用的。我很喜欢;虽然Django的通用视图允许通过关键字参数进行一些自定义,但是OO泛型视图(如果它们的行为被分成许多单独的方法)可以通过子类化进行更细粒度的自定义,这让我重复自己的次数要少得多。 (当我需要调整Django的通用视图不太允许的东西时,我厌倦了重写相同的创建/更新视图逻辑。)
我在djangosnippets.org发布了一些代码。
我看到的唯一真正的缺点是内部方法调用的激增,这可能会对性能产生一些影响。我不认为这是一个值得关注的问题;很少有Python代码执行会成为您在Web应用程序中的性能瓶颈。
更新:Django自己的generic views现在已经基于类。
更新:FWIW,我已经改变了对基于类的视图的看法,因为这个答案是写的。在几个项目中广泛使用它们之后,我觉得它们往往会导致编写令人满意的DRY,但后来很难阅读和维护,因为功能分布在很多不同的地方,而且子类如此依赖关于超类和mixins的每个实现细节。我现在觉得TemplateResponse和视图装饰器是分解视图代码的更好答案。
答案 1 :(得分: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)
我现在可以实例化视图类并将实例用作视图函数,或者我可以简单地将我的URLconf指向我的类并让metaclass为我实例化(并调用)视图类。这通过检查__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/发布了一个代码段)
答案 2 :(得分:10)
如果您只是显示模型中的数据,为什么不使用Django Generic Views?它们旨在让您轻松地显示模型中的数据,而无需编写自己的视图以及将URL参数映射到视图,获取数据,处理边缘情况,渲染输出等内容。
答案 3 :(得分:3)
您始终可以创建一个类,覆盖 __call__
函数,然后将URL文件指向该类的实例。您可以查看FormWizard课程,了解如何完成此操作。
答案 4 :(得分:2)
听起来像你在尝试将不应该合并的东西组合在一起。如果您需要在视图中进行不同的处理,具体取决于它是您要查看的用户或组对象,那么您应该使用两种不同的视图函数。
另一方面,你可能想要从你的object_detail类型视图中提取出常见的习语...也许你可以使用装饰器或只是辅助函数?
-Dan
答案 5 :(得分:2)
除非你想做一些复杂的事情,否则使用通用视图是可行的方法。它们比它们的名字暗示的要强大得多,如果你只是显示模型数据,通用视图就可以完成这项工作。
答案 6 :(得分:1)
如果您想在页面之间共享常用功能,我建议您查看自定义标签。他们非常easy to create,非常强大。
此外,templates can extend from other templates。这允许您有一个基本模板来设置页面的布局,并在填充空白的其他模板之间共享。您可以将模板嵌套到任何深度;允许您在一个地方的不同相关页面组中指定布局。
答案 7 :(得分:1)
通用视图通常是要走的路,但最终你可以自由地处理你想要的URL。 FormWizard以基于类的方式执行操作,RESTful API的一些应用程序也是如此。
基本上有一个URL,你会得到一堆变量和地方来提供一个可调用的,你提供的可调用内容完全取决于你 - 标准的方法是提供一个函数 - 但最终Django对你做的事情没有任何限制
我同意更多关于如何做到这一点的例子会很好,FormWizard可能是开始的地方。
答案 8 :(得分:1)
您可以使用Django通用视图。您可以通过Django generic views
轻松实现所需的功能