Django测验应用表单提交后禁用方法及课堂应用考试表单单次访问权限实现咨询
Hey fellow dev! I see you're building a classroom exam app, and you've got two solid requirements to nail down. Let's break them down with practical, Django-specific solutions that fit your use case:
1. Disabling Form Submission After It's Been Submitted
You want to stop students from resubmitting the exam form once they've finished. This needs both front-end instant feedback (so the user knows right away) and back-end hard protection (to block sneaky direct requests or refresh-based resubmissions).
Front-End Approach (Immediate Visual Feedback)
Add a simple JavaScript snippet to your exam template to disable the submit button and form fields the moment the form is submitted. This prevents accidental double-clicks and gives clear feedback:
<form id="exam-form" method="post"> {% csrf_token %} <!-- Your exam question fields go here --> <button type="submit" id="submit-btn">Submit Exam</button> </form> <script> const examForm = document.getElementById('exam-form'); const submitBtn = document.getElementById('submit-btn'); examForm.addEventListener('submit', function(e) { // Disable the submit button first submitBtn.disabled = true; submitBtn.textContent = 'Submitting...'; // Optional: Disable all form fields to prevent edits mid-submission const allFields = examForm.querySelectorAll('input, select, textarea'); allFields.forEach(field => field.disabled = true); }); </script>
Back-End Approach (Block Unauthorized Resubmissions)
Front-end checks aren't enough—you need to enforce this on the server. Use Django view logic to check if the student has already submitted this exam, and reject any duplicate attempts:
# views.py from django.shortcuts import render, redirect, get_object_or_404 from .models import Exam, ExamAttempt from .forms import ExamForm def take_exam(request, exam_id): exam = get_object_or_404(Exam, id=exam_id) student = request.user # Assuming you're using Django's auth system for students # Check if student already attempted this exam if ExamAttempt.objects.filter(student=student, exam=exam).exists(): return redirect('exam_result', exam_id=exam_id) # Redirect to their results if request.method == 'POST': form = ExamForm(request.POST, exam=exam) if form.is_valid(): # Log the attempt first (critical for access control) ExamAttempt.objects.create(student=student, exam=exam) # Process and save the student's answers here form.save() return redirect('exam_result', exam_id=exam_id) else: form = ExamForm(exam=exam) return render(request, 'take_exam.html', {'form': form, 'exam': exam})
Also, stick to the POST/REDIRECT/GET pattern (like the redirect above) so refreshing the page after submission doesn't trigger another form submit.
2. Restricting Students to Access the Exam Form Only Once
This builds on the back-end check above, but let's formalize the setup to lock down access completely:
Step 1: Create an ExamAttempt Tracking Model
First, add a model to record which students have taken which exams. This is your source of truth for access control:
# models.py from django.db import models from django.contrib.auth.models import User from .models import Exam # Your existing Exam model class ExamAttempt(models.Model): student = models.ForeignKey(User, on_delete=models.CASCADE, related_name='exam_attempts') exam = models.ForeignKey(Exam, on_delete=models.CASCADE, related_name='attempts') submitted_at = models.DateTimeField(auto_now_add=True) class Meta: unique_together = ('student', 'exam') # Guarantees one attempt per student-exam pair
Run migrations to apply this model:
python manage.py makemigrations python manage.py migrate
Step 2: Enforce Access in the View
As shown earlier, in your exam view, check for an existing ExamAttempt before rendering the form. If one exists, redirect to a "already attempted" page or results:
# In take_exam view if ExamAttempt.objects.filter(student=student, exam=exam).exists(): return render(request, 'already_attempted.html', {'exam': exam})
Step 3: Optional: Reusable Access Control Decorator
If you want to reuse this check across multiple views, create a custom decorator:
# decorators.py from django.shortcuts import get_object_or_404, redirect from .models import Exam, ExamAttempt def can_take_exam(view_func): def wrapper(request, exam_id, *args, **kwargs): exam = get_object_or_404(Exam, id=exam_id) if ExamAttempt.objects.filter(student=request.user, exam=exam).exists(): return redirect('already_attempted') return view_func(request, exam_id, *args, **kwargs) return wrapper # Use it in views.py like this: @can_take_exam def take_exam(request, exam_id): # Your view logic here
This way, any student trying to navigate back to the exam URL after submitting will be blocked automatically.
内容的提问来源于stack exchange,提问作者Ashish




