You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Django测验应用表单提交后禁用方法及课堂应用考试表单单次访问权限实现咨询

Django Quiz App: Two Key Features Implementation

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

火山引擎 最新活动