Django侧边栏点击链接后Submissions列表消失问题排查
我正在开发一个Django项目,需在侧边栏展示Submissions列表。侧边栏嵌入基础模板main.html,其他模板均继承该模板。首页时侧边栏能正常显示所有Submissions,但点击侧边栏中的某个Submission后,页面跳转正确,但侧边栏仅显示被点击的Submission,其余条目全部消失。
相关代码
Models.py
from django.db import models from users.models import UserProfile # Create your models here. class ResearchWork(models.Model): name = models.CharField(max_length=100) description = models.TextField() def __str__(self): return self.name class Assignment(models.Model): student = models.ForeignKey(UserProfile, related_name='student_assignment', on_delete=models.CASCADE) teacher = models.ForeignKey(UserProfile, related_name='teacher_assignment', on_delete=models.CASCADE) is_accepted = models.BooleanField(default=False) created_at = models.DateTimeField(auto_now_add=True) text = models.TextField(blank=True) def __str__(self): return f"Assignment for {self.student.user.username} with {self.teacher.user.username}" class Submission(models.Model): assignment = models.ForeignKey(Assignment, on_delete=models.CASCADE) SEMESTER_CHOICES = ( ('1', 'Semester 1'), ('2', 'Semester 2'), ('3', 'Semester 3'), ('4', 'Semester 4'), ('5', 'Semester 5'), ('6', 'Semester 6'), ('7', 'Semester 7'), ('8', 'Semester 8'), ) semester = models.CharField(max_length=100, null=True, choices=SEMESTER_CHOICES) research_work = models.ForeignKey(ResearchWork, on_delete=models.CASCADE, null=True) created_at = models.DateTimeField(auto_now_add=True, null=True) def __str__(self): research_work_name = "No Research Work Assigned" if self.research_work is None else self.research_work.name return f"{research_work_name} - for student {self.assignment.student.user.username} in semester - {self.semester}"
Context Processor
from base.models import Submission def user_profile_pk(request): context = {} if request.user.is_authenticated: user_profile_pk = request.user.userprofile.pk context['user_profile_pk'] = user_profile_pk student = request.user.userprofile submissions = Submission.objects.filter(assignment__student=student) context['submissions'] = submissions else: context['user_profile_pk'] = None context['submissions'] = None print(f"Submissions for {student}: {submissions}") return context
Settings.py
TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [ BASE_DIR / 'templates' ], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', 'users.context_processors.user_profile_pk', ], }, }, ]
模板遍历代码
{% for submission in submissions %} <li class="nav-item"> <a class="nav-link" href="{% url 'research-work-detail' rw_id=submission.research_work.id semester=submission.semester subm_id=submission.id %}" ><span class="nav-icon"></span>{{submission.research_work.name}} - Сем.{{submission.semester}}</a > </li> {% endfor %}
Urls.py
urlpatterns = [ path('login/', views.loginPage, name='login'), path('home/', views.home, name='home'), path('student/<str:pk>/', views.student_home, name='student-home'), path('research-work/<int:rw_id>/<str:semester>/<int:subm_id>/', views.research_work_detail, name='research-work-detail'), path('topics/<int:rw_id>/<int:topic_id>/<int:subm_id>/', views.upload_page, name='upload-page'), path('upload-file/<int:subm_id>/<int:topic_id>/', views.upload_file, name='upload-file'), path('choose-teacher/<int:student_id>/', views.choose_teacher, name='choose-teacher'), ] urlpatterns += static(settings.MEDIA_URL, document_root = settings.MEDIA_ROOT) urlpatterns += static(settings.STATIC_URL, document_root = settings.STATIC_ROOT)
views.py - research_work_detail
def research_work_detail(request, rw_id, semester, subm_id): research_work = get_object_or_404(ResearchWork, pk=rw_id) submissions = Submission.objects.filter(research_work=research_work, semester=semester) submission = get_object_or_404(Submission, pk=subm_id) topics = Topic.objects.filter(research_work=research_work) context = {'research_work': research_work, 'submissions':submissions, 'topics': topics, 'submission_id':submission.id } return render(request, 'users/topics.html', context=context)
核心是变量名冲突:上下文处理器会给所有模板传递当前用户的所有Submissions,但在research_work_detail视图中,你重新定义了submissions变量,它的值是Submission.objects.filter(research_work=research_work, semester=semester)——这个查询只会返回当前详情页对应的同ResearchWork、同Semester的Submission(通常只有一条)。
Django模板渲染时,视图传递的上下文变量优先级高于上下文处理器的变量,所以侧边栏遍历submissions时,实际使用的是视图传递的窄范围数据,导致只显示一条。
推荐以下两种修复方式:
方式一:重命名视图中的变量(最优)
将视图里的submissions变量改为其他名称,避免覆盖上下文处理器的变量:
def research_work_detail(request, rw_id, semester, subm_id): research_work = get_object_or_404(ResearchWork, pk=rw_id) # 重命名变量,避免与上下文处理器的submissions冲突 current_submissions = Submission.objects.filter(research_work=research_work, semester=semester) submission = get_object_or_404(Submission, pk=subm_id) topics = Topic.objects.filter(research_work=research_work) context = { 'research_work': research_work, 'current_submissions': current_submissions, 'topics': topics, 'submission_id': submission.id } return render(request, 'users/topics.html', context=context)
这样模板侧边栏的{% for submission in submissions %}会正常使用上下文处理器传递的用户所有Submissions,视图所需的特定数据则用current_submissions调用即可。
方式二:在视图中显式传递用户所有Submissions
如果视图逻辑需要同时使用用户所有Submissions和当前详情页的Submissions,也可以在视图中重新获取并传递(但不如方式一高效,因为上下文处理器已经做了这个工作):
def research_work_detail(request, rw_id, semester, subm_id): research_work = get_object_or_404(ResearchWork, pk=rw_id) current_submissions = Submission.objects.filter(research_work=research_work, semester=semester) submission = get_object_or_404(Submission, pk=subm_id) topics = Topic.objects.filter(research_work=research_work) # 复用上下文处理器的逻辑,获取用户所有Submissions if request.user.is_authenticated: student = request.user.userprofile submissions = Submission.objects.filter(assignment__student=student) else: submissions = None context = { 'research_work': research_work, 'current_submissions': current_submissions, 'topics': topics, 'submission_id': submission.id, 'submissions': submissions } return render(request, 'users/topics.html', context=context)
内容的提问来源于stack exchange,提问作者Nika

