在Django中创建假请求以将视图渲染为字符串
问题
我想在一个视图里渲染另一个视图,也就是调用那个视图(获取响应并提取渲染后的内容),然后把它变成字符串。问题是,我希望在渲染这个视图的时候,有一个虚拟用户“登录”,同时还想对请求中的一些小细节进行修改。我希望避免的是从头开始构建一个请求,因为在父视图中,我有90%的请求内容是相同的。
我在想,关于最佳实践和技术方面,我应该怎么做比较好?
我现在考虑的方式是这样的:(但我总觉得这方法不好,肯定还有更好的办法,只是我想不出来)
处理视图的内容...
把当前用户登出
创建/登录虚拟用户
稍微修改一下请求
把视图渲染成字符串
登出虚拟用户
把原来的用户重新登录
视图处理结束...
有没有什么想法?或者能指引我更好的方向?
谢谢,
dennmat
3 个回答
只需使用测试客户端 - 它不仅仅适合测试:
from django.test import Client
c = Client()
# login if necessary
c.login(username='dummy', password='user')
# get the view
response = c.get(reverse('my-view', args=[foo,bar])
html = response.content
从1.6版本开始,这个用法甚至有官方文档说明,不过在旧版本中也能用:https://docs.djangoproject.com/en/1.6/topics/testing/tools/#module-django.test.client
根据你在视图中依赖请求信息的程度,最好的做法可能是创建一个函数来处理视图中的所有繁琐工作,而让你的实际视图只需将所需的值传递给这个函数。也就是说,不要让视图函数直接处理请求,而是创建一个新的函数,让它接收用户信息:
def _real_view(user):
return render_to_response('template.html', {'user' : user})
def view(request):
# Now both of these are possible...
response = _real_view(User.objects.get(5))
response = _real_view(request.user)
return response
这样,当你想用不同的用户来显示视图时,只需要获取那个用户的信息,然后把它传递给视图就可以了。这样就不需要去改变当前用户或者修改请求了。
其实你并不需要把当前用户登出,你可以直接在你打算用来显示其他页面的HttpRequest
对象中更改用户。你可以这样做:
from django.contrib.auth.models import User
from django.http import HttpResponse
def view_inside_a_view(request):
return HttpResponse('hello %s' % request.user)
def view(request):
# change to dummy user, or whoever
request.user = User.objects.get(id=1)
response = view_inside_a_view(request)
return HttpResponse('rendered view: %s' % response.content)
如果你需要登录一个假用户,可以使用django.contrib.auth.authenticate
或者django.contrib.auth.login
来实现。下面是使用login
的例子(这样就不需要使用假用户的密码):
from django.contrib.auth.models import User
from django.contrib.auth import login, get_backends
from django.contrib.auth.decorators import login_required
from django.http import HttpResponse
@login_required
def view_inside_a_view(request):
return HttpResponse('hello %s' % request.user)
def view(request):
# login dummy user
user = User.objects.get(id=2)
backend = get_backends()[0]
user.backend = "%s.%s" % (backend.__module__, backend.__class__.__name__)
login(request, user)
# change request's user
request.user = user
# get response from view
response = view_inside_a_view(request)
return HttpResponse('rendered view: %s' % response.content)