Creating a fake request to render a view to a string in django
Problem
I'd like to render an arbitrary view, by calling the view (capture the response and extract the rendered content), to a string, inside another view. The problem being I'd like to have a dummy user "logged-in" during the rendering of that view, along with changing a few other minor things in the request. What I'd like to avoid is building a request completely from scratch, as 90% of the request I'll have at hand in the parent view will be the same.
I'm wondering how I should go about this as far as best practice is concerned, as well as technically?
I'm currently thinking something like this: (But I can't help but feel this is horrible and there's got to be a better way, I just cannot think of it)
View stuff...
Log current user out
Create/Login dummy user
Somehow modify request a bit
Render view to string
Log out dummy user
Log back in original user
End of view stuff.开发者_Go百科..
Any ideas? Or a pointer into a better direction?
Thanks, dennmat
Depending upon how much you're relying on getting information from the request during the view, it might be best that you just create a function to do all of the view's dirty work, and have your real view just pass in the values it needs into this function. So, instead of a view function that takes a request, create another function that takes a user:
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
Then, when you want to a view using a different user, you only need to grab the information for that user and pass it into the view. No need to change the current user or modify the request at all.
You don't actually need to log the current user out, you could just change the user in the HttpRequest
object you plan to use to render the other view. You could do something like this:
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)
If you need to login your dummy user you could use django.contrib.auth.authenticate
or or django.contrib.auth.login
to do so. Example using login
(avoids necessity of using dummy user's password):
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)
just use the test client - it's not only good for testing:
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
Since 1.6 this is even officially documented, however it works in older versions too: https://docs.djangoproject.com/en/1.6/topics/testing/tools/#module-django.test.client
精彩评论