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

如何在Django中用ModelChoiceFields实现二级下拉动态联动

Alright, let's tackle this dynamic category-subcategory dropdown requirement in Django. This is a pretty common use case, and we can make it work smoothly with a mix of backend setup and frontend AJAX calls—no need to submit the entire form to update the subcategories.

Solution for Dynamic Category-Subcategory Dropdowns

1. Update Your Form Definition

First, we need to initialize the subcategory field with an empty queryset since we’ll populate it dynamically. I’m assuming your SubCategory model already has a foreign key relationship to Category (like category = models.ForeignKey(Category, on_delete=models.CASCADE)—if not, set that up first!).

class AddProductForm(forms.Form):
    category = forms.ModelChoiceField(
        widget=forms.Select(attrs={'class': 'form-control'}),
        queryset=Category.objects.all(),
        to_field_name="category"
    )
    sub_category = forms.ModelChoiceField(
        widget=forms.Select(attrs={'class': 'form-control'}),
        queryset=SubCategory.objects.none()  # Start with empty options
    )

2. Create a Backend View to Fetch Subcategories

We’ll build a simple view that takes a category ID and returns matching subcategories as JSON. This will be the endpoint our frontend calls when the user selects a different category.

from django.http import JsonResponse
from .models import SubCategory

def get_subcategories(request):
    category_id = request.GET.get('category_id')
    # Adjust 'sub_category' below to match your actual display field name in SubCategory
    subcategories = SubCategory.objects.filter(category_id=category_id).values('id', 'sub_category')
    return JsonResponse(list(subcategories), safe=False)

3. Map the View to a URL

Add this path to your app’s urls.py so the frontend can access the endpoint:

from django.urls import path
from . import views

urlpatterns = [
    # ... your existing URLs
    path('get-subcategories/', views.get_subcategories, name='get_subcategories'),
]

4. Add Frontend AJAX Logic

Now we need to listen for changes on the category dropdown, fetch the corresponding subcategories, and update the subcategory dropdown in real-time. I’ll show both jQuery and vanilla JS options—pick whichever fits your project.

Using jQuery (Simpler for Most Projects)

Make sure you include jQuery in your template first, then add this script:

<script src="https://code.jquery.com/jquery-3.7.0.min.js"></script>
<script>
$(document).ready(function() {
    const $category = $('#id_category');
    const $subCategory = $('#id_sub_category');

    // Triggered when category selection changes
    $category.change(function() {
        const categoryId = $(this).val();
        
        $.ajax({
            url: "{% url 'get_subcategories' %}",
            data: { 'category_id': categoryId },
            dataType: 'json',
            success: function(data) {
                // Clear old options and add a placeholder
                $subCategory.empty();
                $subCategory.append('<option value="">-- Select Sub Category --</option>');
                
                // Populate new subcategory options
                $.each(data, function(index, subcat) {
                    $subCategory.append(`<option value="${subcat.id}">${subcat.sub_category}</option>`);
                });
            }
        });
    });

    // Optional: Auto-load subcategories if a category is pre-selected
    if ($category.val()) {
        $category.trigger('change');
    }
});
</script>

Using Vanilla JavaScript (No jQuery Needed)

If you prefer to avoid jQuery, use this script instead:

<script>
document.addEventListener('DOMContentLoaded', function() {
    const categoryDropdown = document.getElementById('id_category');
    const subcategoryDropdown = document.getElementById('id_sub_category');

    categoryDropdown.addEventListener('change', function() {
        const categoryId = this.value;
        const url = `{% url 'get_subcategories' %}?category_id=${categoryId}`;

        fetch(url)
            .then(response => response.json())
            .then(data => {
                // Clear existing options
                subcategoryDropdown.innerHTML = '';
                
                // Add placeholder option
                const placeholder = document.createElement('option');
                placeholder.value = '';
                placeholder.textContent = '-- Select Sub Category --';
                subcategoryDropdown.appendChild(placeholder);
                
                // Add subcategory options
                data.forEach(subcat => {
                    const option = document.createElement('option');
                    option.value = subcat.id;
                    option.textContent = subcat.sub_category;
                    subcategoryDropdown.appendChild(option);
                });
            });
    });

    // Auto-load if category is pre-selected
    if (categoryDropdown.value) {
        categoryDropdown.dispatchEvent(new Event('change'));
    }
});
</script>

Quick Notes to Avoid Issues

  • Double-check your SubCategory model field names: replace sub_category in the view and frontend code with the actual field that stores the subcategory’s display name.
  • Since we’re using a GET request here, we don’t need to handle Django’s CSRF token. If you switch to POST later, you’ll need to include the CSRF token in the request headers.
  • Adjust the required status of the sub_category form field based on your needs (add required=True if users must select a subcategory).

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

火山引擎 最新活动