我正在Django中编写一个应用程序,它在url中使用[year]/[month]/[title-text]
来识别新闻项目。为了管理项目,我已经定义了许多网址,每个网址都以上面的前缀开头。
urlpatterns = patterns('msite.views',
(r'^(?P<year>[\d]{4})/(?P<month>[\d]{1,2})/(?P<slug>[\w]+)/edit/$', 'edit'),
(r'^(?P<year>[\d]{4})/(?P<month>[\d]{1,2})/(?P<slug>[\w]+)/$', 'show'),
(r'^(?P<year>[\d]{4})/(?P<month>[\d]{1,2})/(?P<slug>[\w]+)/save$', 'save'),
)
我想知道,如果Django中有一个机制,它允许我对视图edit
,show
和save
预先处理一个请求。它可以解析参数,例如year=2010, month=11, slug='this-is-a-title'
并从中提取模型对象。
好处是,我可以将我的观点定义为
def show(news_item):
'''does some stuff with the news item, doesn't have to care
about how to extract the item from request data'''
...
而不是
def show(year, month, slug):
'''extract the model instance manually inside this method'''
...
Django解决这个问题的方法是什么? 或者以更通用的方式,是否有一些机制来实现请求过滤器/预处理器,例如在JavaEE和Ruby on Rails中?
答案 0 :(得分:2)
答案 1 :(得分:1)
这样做的一种方法是编写自定义装饰器。我在我的一个项目中对此进行了测试,并且工作正常。
首先,自定义装饰器。这个必须接受函数旁边的其他参数,所以我们声明另一个装饰器来实现它。
decorator_with_arguments = lambda decorator: lambda * args, **kwargs: lambda func: decorator(func, *args, **kwargs)
现在是实际的装饰者:
@decorator_with_arguments
def parse_args_and_create_instance(function, klass, attr_names):
def _function(request, *args, **kwargs):
model_attributes_and_values = dict()
for name in attr_names:
value = kwargs.get(name, None)
if value: model_attributes_and_values[name] = value
model_instance = klass.objects.get(**model_attributes_and_values)
return function(model_instance)
return _function
除了正在装饰的函数之外,这个装饰器还需要两个额外的参数。它们分别是要为其准备和注入实例的模型类,以及用于准备实例的属性的名称。在这种情况下,装饰器使用来自数据库的get
实例的属性。
现在,使用show
函数的“通用”视图。
def show(model_instance):
return HttpResponse(model_instance.some_attribute)
show_order = parse_args_and_create_instance(Order, ['order_id'])(show)
另一个:
show_customer = parse_args_and_create_instance(Customer, ['id'])(show)
为了使其工作,URL配置参数必须包含与属性相同的关键字。当然你可以通过调整装饰器来定制它。
# urls.py
...
url(r'^order/(?P<order_id>\d+)/$', 'show_order', {}, name = 'show_order'),
url(r'^customer/(?P<id>\d+)/$', 'show_customer', {}, name = 'show_customer'),
...
<强>更新强>
正如@rebus正确pointed out,您还需要调查Django的通用视图。
答案 2 :(得分:0)
毕竟Django是python,所以你可以很容易地做到这一点:
def get_item(*args, **kwargs):
year = kwargs['year']
month = kwargs['month']
slug = kwargs['slug']
# return item based on year, month, slug...
def show(request, *args, **kwargs):
item = get_item(request, *args, **kwargs)
# rest of your logic using item
# return HttpResponse...