在Django中创建假请求以将视图渲染为字符串

4 投票
3 回答
4517 浏览
提问于 2025-04-17 00:56

问题

我想在一个视图里渲染另一个视图,也就是调用那个视图(获取响应并提取渲染后的内容),然后把它变成字符串。问题是,我希望在渲染这个视图的时候,有一个虚拟用户“登录”,同时还想对请求中的一些小细节进行修改。我希望避免的是从头开始构建一个请求,因为在父视图中,我有90%的请求内容是相同的。

我在想,关于最佳实践和技术方面,我应该怎么做比较好?

我现在考虑的方式是这样的:(但我总觉得这方法不好,肯定还有更好的办法,只是我想不出来)

处理视图的内容...

把当前用户登出

创建/登录虚拟用户

稍微修改一下请求

把视图渲染成字符串

登出虚拟用户

把原来的用户重新登录

视图处理结束...

有没有什么想法?或者能指引我更好的方向?

谢谢,

dennmat

3 个回答

1

只需使用测试客户端 - 它不仅仅适合测试:

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

2

根据你在视图中依赖请求信息的程度,最好的做法可能是创建一个函数来处理视图中的所有繁琐工作,而让你的实际视图只需将所需的值传递给这个函数。也就是说,不要让视图函数直接处理请求,而是创建一个新的函数,让它接收用户信息:

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

这样,当你想用不同的用户来显示视图时,只需要获取那个用户的信息,然后把它传递给视图就可以了。这样就不需要去改变当前用户或者修改请求了。

1

其实你并不需要把当前用户登出,你可以直接在你打算用来显示其他页面的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)

撰写回答