Django:传递变量至其他函数并渲染HTML模板的可行方案探讨
问题
希望在views.py的所有视图函数中访问同一个非常量变量,但无法将其设为全局变量。咨询:是否可以在将变量(如登录函数loginpage中的currentUser)传递给另一个函数的同时渲染HTML模板?若该方式不可行,有哪些替代方案?
登录函数代码:
def loginpage(request): errorMessage = '' # Applicant Login if request.method=="POST": if request.POST.get('username') and request.POST.get('pwd'): try: currentUser=Applicant.objects.get(username=request.POST['username'],pwd=request.POST['pwd']) currentUser=Applicant.objects.get(username=request.POST['username']) first = currentUser.firstname middle = currentUser.middleinitial last = currentUser.lastname AppDashboard = ApplicantDashboardPageView(currentUser, request) except Applicant.DoesNotExist as e: errorMessage = 'Invalid username/password!' return render(request, 'home.html')
目标函数代码:
def ApplicantdashboardPageView(currentUser, request): appPeriod = ApplicationPeriod.objects.all() exam = ExaminationSchedule.objects.all() posts = Post.objects.all().order_by('-created_on') form = PostForm() name=userNaCurrent print('from storeCurrentUser', name) if request.method == "GET": try: posts = Post.objects.all().order_by('-created_on') form = PostForm() #applicantID=currentUser.id #applicantNotification = Applicant.objects.get(id=applicantID) return render(request, 'applicantdashboard.html', context={'UserName' : name, 'posts':posts, 'appPeriod':appPeriod, 'exam':exam}) except ObjectDoesNotExist: return render(request, 'applicantdashboard.html', context={'UserName' : name, 'posts':posts,}) return render(request, 'applicantdashboard.html', context={'UserName' : name, 'posts':posts, 'appPeriod':appPeriod, 'exam':exam})
注:本人是Django新手,若问题较为基础请见谅。
解决方案
一、直接传递变量并渲染模板的可行性
你当前的写法AppDashboard = ApplicantDashboardPageView(currentUser, request)不可行,原因有两点:
- Django视图函数的规范是第一个参数必须是
request,目标函数把currentUser放在request前面,不符合Django的视图调用规则,会导致路由请求出错。 - 即使调整参数顺序,直接在
loginpage里调用视图函数也无法完成页面跳转或渲染——loginpage最后还是会返回home.html的渲染结果,目标函数的返回值会被直接忽略。
如果想登录成功后直接跳转到仪表盘页面,应该用redirect结合URL路由,而非直接调用视图函数。
二、替代方案(实现多视图共享currentUser)
1. 使用Django Session(最常用)
Django的Session可以存储用户标识,后续请求中取出并查询用户对象,实现跨视图共享。
修改loginpage函数:
def loginpage(request): errorMessage = '' if request.method=="POST": if request.POST.get('username') and request.POST.get('pwd'): try: # 优化查询:一次验证用户名密码 currentUser=Applicant.objects.get(username=request.POST['username'],pwd=request.POST['pwd']) # 将用户ID存入session request.session['applicant_id'] = currentUser.id # 登录成功后跳转到仪表盘页面(对应urls.py中仪表盘路由的name) return redirect('applicant_dashboard') except Applicant.DoesNotExist: errorMessage = 'Invalid username/password!' return render(request, 'home.html', {'errorMessage': errorMessage})
修改ApplicantdashboardPageView函数:
from django.shortcuts import get_object_or_404, redirect def ApplicantdashboardPageView(request): # 从session中获取用户ID,不存在则跳转到登录页 applicant_id = request.session.get('applicant_id') if not applicant_id: return redirect('login') # 对应登录页路由的name currentUser = get_object_or_404(Applicant, id=applicant_id) name = f"{currentUser.firstname} {currentUser.middleinitial} {currentUser.lastname}" appPeriod = ApplicationPeriod.objects.all() exam = ExaminationSchedule.objects.all() posts = Post.objects.all().order_by('-created_on') form = PostForm() context = { 'UserName': name, 'posts': posts, 'appPeriod': appPeriod, 'exam': exam, 'form': form } return render(request, 'applicantdashboard.html', context)
2. 使用自定义装饰器
如果多个视图都需要获取currentUser,可以写一个装饰器,自动从session中取出用户并注入到视图函数中。
自定义装饰器:
from django.shortcuts import redirect, get_object_or_404 def require_applicant_login(view_func): def wrapper(request, *args, **kwargs): applicant_id = request.session.get('applicant_id') if not applicant_id: return redirect('login') currentUser = get_object_or_404(Applicant, id=applicant_id) # 将currentUser作为参数传递给视图函数 return view_func(request, currentUser, *args, **kwargs) return wrapper
给仪表盘视图添加装饰器:
@require_applicant_login def ApplicantdashboardPageView(request, currentUser): name = f"{currentUser.firstname} {currentUser.middleinitial} {currentUser.lastname}" # 后续逻辑与上面的仪表盘视图一致
3. 使用上下文处理器(全局模板可用)
如果不仅视图函数需要,模板也需要全局访问currentUser,可以配置上下文处理器。
在settings.py的TEMPLATES中添加自定义上下文处理器:
TEMPLATES = [ { # ...其他配置 'OPTIONS': { 'context_processors': [ # ...默认处理器 'your_app_name.context_processors.applicant_context', ], }, }, ]
在你的app下创建context_processors.py:
from django.shortcuts import get_object_or_404 def applicant_context(request): context = {} applicant_id = request.session.get('applicant_id') if applicant_id: try: currentUser = Applicant.objects.get(id=applicant_id) context['currentUser'] = currentUser context['UserName'] = f"{currentUser.firstname} {currentUser.middleinitial} {currentUser.lastname}" except Applicant.DoesNotExist: pass return context
配置完成后,所有模板都可以直接使用{{ currentUser }}和{{ UserName }},无需在视图中单独传递。
4. 使用类视图Mixin(适合类视图场景)
如果用类视图编写页面,可以写一个Mixin类处理用户认证:
from django.views.generic import TemplateView from django.shortcuts import redirect, get_object_or_404 class ApplicantLoginRequiredMixin: def dispatch(self, request, *args, **kwargs): applicant_id = request.session.get('applicant_id') if not applicant_id: return redirect('login') self.currentUser = get_object_or_404(Applicant, id=applicant_id) return super().dispatch(request, *args, **kwargs) class ApplicantDashboardPageView(ApplicantLoginRequiredMixin, TemplateView): template_name = 'applicantdashboard.html' def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) name = f"{self.currentUser.firstname} {self.currentUser.middleinitial} {self.currentUser.lastname}" context['UserName'] = name context['appPeriod'] = ApplicationPeriod.objects.all() context['exam'] = ExaminationSchedule.objects.all() context['posts'] = Post.objects.all().order_by('-created_on') context['form'] = PostForm() return context
内容的提问来源于stack exchange,提问作者bubble
相关产品推荐
相关产品推荐

