You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django模型关系管理及选课表单动态显示课程价格时长方案

Fixes for Dynamic Course Info Display & ManyToMany Save Error

Hey there! Let's tackle your two issues one by one—first the student.course.set() error, then adding dynamic course details to your student form.

1. Fixing the student.course.set() Error

The error happens because the set() method for ManyToMany fields requires an iterable of objects/IDs to associate with the student. But actually, you don't need to manually call this at all when using a ModelForm. Here's why:

  • When you use form.save(), the ModelForm automatically handles saving ManyToMany relationships for you.
  • If you use commit=False to modify the student before saving, you just need to call form.save_m2m() afterward to persist the course associations.

Here's the corrected addstudent view:

def addstudent(request):
    if request.method == 'POST':
        form = AddStudentForm(request.POST)
        if form.is_valid():
            # If you don't need to modify the student instance, just do:
            # form.save()
            # If you do need to modify it first:
            student = form.save(commit=False)
            # Add any custom modifications here (e.g., student.some_field = value)
            student.save()
            form.save_m2m()  # This saves the ManyToMany course relationships
            return redirect('/student/view/student/')
    else:
        form = AddStudentForm()
    return render(request,'student/add_student.html',{'form':form})

2. Adding Dynamic Course Info Display

To show the selected course's price and duration dynamically, we'll use JavaScript to listen for changes in the course selection, then pull and display the course's details. We'll store the course data directly in the form options using HTML data-* attributes for simplicity.

Step 1: Update the Student Form (forms.py)

We'll override the course field to ensure we can pass extra data to the template:

class AddStudentForm(forms.ModelForm):
    course = forms.ModelMultipleChoiceField(
        queryset=Course.objects.all(),
        widget=forms.SelectMultiple(attrs={'id': 'course-select'}),
        required=True
    )

    class Meta:
        model = Student
        fields = '__all__'

(Note: If you want a single course selection instead of multiple, use ModelChoiceField with Select widget instead.)

Step 2: Modify the Add Student Template (add_student.html)

We'll manually render the course field to add data-* attributes to each option, then add a section to display the course details, plus the JavaScript to update it:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Add Student</title>
    <style>
        .course-details {
            margin: 20px 0;
            padding: 15px;
            border: 1px solid #ccc;
            border-radius: 4px;
        }
    </style>
</head>
<body>
<form action="" method="post" >
    {% csrf_token %}
    
    <!-- Render other fields normally -->
    {{ form.name.as_p }}
    {{ form.phone.as_p }}
    {{ form.email.as_p }}
    {{ form.address.as_p }}

    <!-- Manually render course field to add data attributes -->
    <p>
        <label for="{{ form.course.id_for_label }}">Course:</label>
        <select multiple id="{{ form.course.id_for_label }}" name="{{ form.course.name }}">
            {% for course in form.course.queryset %}
                <option value="{{ course.id }}" 
                    data-basic-price="{{ course.basic_price }}"
                    data-advanced-price="{{ course.advanced_price }}"
                    data-basic-duration="{{ course.basic_duration }}"
                    data-advanced-duration="{{ course.advanced_duration }}">
                    {{ course.title }}
                </option>
            {% endfor %}
        </select>
    </p>

    <!-- Section to display course details -->
    <div class="course-details" id="course-details" style="display: none;">
        <h4>Selected Course Details:</h4>
        <p><strong>Basic Price:</strong> <span id="basic-price"></span></p>
        <p><strong>Advanced Price:</strong> <span id="advanced-price"></span></p>
        <p><strong>Basic Duration:</strong> <span id="basic-duration"></span></p>
        <p><strong>Advanced Duration:</strong> <span id="advanced-duration"></span></p>
    </div>

    <input type="submit" class="btn btn-success text-center w-100 mb-3" value="Add">
</form>

<script>
    const courseSelect = document.getElementById('course-select');
    const courseDetails = document.getElementById('course-details');
    const basicPriceSpan = document.getElementById('basic-price');
    const advancedPriceSpan = document.getElementById('advanced-price');
    const basicDurationSpan = document.getElementById('basic-duration');
    const advancedDurationSpan = document.getElementById('advanced-duration');

    // Listen for changes in course selection
    courseSelect.addEventListener('change', function() {
        // Get the first selected course (adjust if you want to handle multiple selections)
        const selectedOption = this.options[this.selectedIndex];
        if (selectedOption) {
            // Populate the details from data attributes
            basicPriceSpan.textContent = selectedOption.dataset.basicPrice;
            advancedPriceSpan.textContent = selectedOption.dataset.advancedPrice;
            basicDurationSpan.textContent = selectedOption.dataset.basicDuration;
            advancedDurationSpan.textContent = selectedOption.dataset.advancedDuration;
            courseDetails.style.display = 'block';
        } else {
            courseDetails.style.display = 'none';
        }
    });

    // Show details if a course is pre-selected (for edit forms)
    if (courseSelect.selectedIndex !== -1) {
        courseSelect.dispatchEvent(new Event('change'));
    }
</script>
</body>
</html>

(If you switched to a single-select dropdown, remove the multiple attribute from the <select> tag—this script will work the same way.)

Notes for Multiple Course Selection

If you want to display details for all selected courses instead of just the first, you can modify the JavaScript to loop through all selected options and generate a list of details. For example:

courseSelect.addEventListener('change', function() {
    const selectedOptions = Array.from(this.selectedOptions);
    if (selectedOptions.length > 0) {
        let detailsHtml = '<h4>Selected Courses Details:</h4>';
        selectedOptions.forEach(option => {
            detailsHtml += `
                <div style="margin-top: 10px; padding-top: 10px; border-top: 1px solid #eee;">
                    <h5>${option.textContent}</h5>
                    <p><strong>Basic Price:</strong> ${option.dataset.basicPrice}</p>
                    <p><strong>Advanced Price:</strong> ${option.dataset.advancedPrice}</p>
                    <p><strong>Basic Duration:</strong> ${option.dataset.basicDuration}</p>
                    <p><strong>Advanced Duration:</strong> ${option.dataset.advancedDuration}</p>
                </div>
            `;
        });
        courseDetails.innerHTML = detailsHtml;
        courseDetails.style.display = 'block';
    } else {
        courseDetails.style.display = 'none';
    }
});

Final Checks

  • Make sure you've run python manage.py migrate to ensure all model changes are applied (though your existing models are fine here).
  • Test the form: Select a course, and you should see the details appear automatically. The student save process will now work without errors.

内容的提问来源于stack exchange,提问作者user11345100

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 05:35:03