Django:如何使依赖下拉列表在更新表单上加载经过筛选的对象列表?

问题描述 投票:0回答:1

我的申请中有多个依赖下拉菜单。要添加新记录,表单将按预期工作;例如,您选择一个

Country
并将加载该
State
Country
对象列表,然后选择一个
State
并将加载该
Suburb
State
对象。您保存记录,它已正确保存所有字段,您查看记录,所有信息都可以按预期查看。

我遇到的问题是当我想更改/更新记录时。实例化的

SuburbForm
被告知首先加载
State
的空白下拉列表,并在设置父对象
load_dropdowns
时调用函数
Country
。调用
load_dropdowns
的操作似乎不会在更新表单中发生,相反,即使我尝试重新选择父级,它也只是保持空白。

如果我更改实例化表单以加载所有对象而不是空白下拉列表,则更新表单会正确填写该字段,但这意味着添加新表单和更新表单现在会加载所有对象而不是过滤列表。

模型.py

from django.db import models

class Country(models.Model):
    item_name = models.CharField(verbose_name="Country")

class State(models.Model):
    item_name = models.CharField(verbose_name="State")
    state_in_country = models.ForeignKey(Country, on_delete=models.SET_NULL, verbose_name="Country", blank=True, null=True)

class Suburb(models.Model):
    item_name = models.CharField(verbose_name="Suburb")
    suburb_in_country = models.ForeignKey(Country, on_delete=models.SET_NULL, verbose_name="Country", blank=True, null=True)
    suburb_in_state = models.ForeignKey(State, on_delete=models.SET_NULL, verbose_name="State", blank=True, null=True)

forms.py

from django import forms
from .models import Country, State, Suburb

class CountryForm(forms.ModelForm):        
    class Meta:
        model = Country
        fields = [
            'item_name'
        ]

class StateForm(forms.ModelForm):
    class Meta:
        model = State
        fields = [
            'item_name', 
            'state_in_country'
        ]

class SuburbForm(forms.ModelForm):

    # separately define fields for dependent dropdowns
    suburb_in_country = forms.ModelChoiceField(queryset=Country.objects.filter(deleted=False),widget=forms.Select(attrs={"hx-get": "load_states_for_suburbform/", "hx-target": "#id_suburb_in_state"}),label="Country")

    # THE FOLLOWING VARIABLE RESULTS IN A BLANK DROPDOWN LIST WHICH CHANGES TO A FILTERED LIST ON ADD NEW FORM BUT REMAINS BLANK ON UPDATE FORM - SEE __init__ BELOW
    suburb_in_state = forms.ModelChoiceField(queryset=State.objects.none(),label="State")
        
    class Meta:
        model = Suburb
        fields = [
            'item_name', 
            'suburb_in_country',
            'suburb_in_state'
        ]

    def __init__(self, *args, **kwargs):
        super(SuburbForm, self).__init__(*args, **kwargs)

        # handle input from dependent dropdowns
        if 'suburb_in_country' in self.data:
            suburb_in_country = int(self.data.get("suburb_in_country"))
            self.fields['suburb_in_state'].queryset = State.objects.filter(state_in_country=suburb_in_country)     

views.py

from django.shortcuts import render,redirect,get_object_or_404
from .forms import *
from .models import *

...
def update(request, id, item):
    item = str_to_class(item)
    page_title = 'Update ' + item._meta.verbose_name
    instance = get_object_or_404(item, id=id)

    if request.method == 'POST':
        form = str_to_class(item._meta.verbose_name.strip() + 'Form')(request.POST, instance=instance)
        if form.is_valid():
            form.save()
        return redirect(item._meta.list_view)
    else:
        form = str_to_class(item._meta.verbose_name.strip() + 'Form')(instance=instance)
                     

    context = {'form':form, 
               'title': page_title,
               'list_view': item._meta.list_view}

    return render(request, 'create.html', context)
...
# Load data for dropdowns that depend on the choice of parent item
# requires model name (item) and the parent field to filter on (parent_field)
def load_dropdowns(request, item, parent_field):
    parent_id = 0 if request.GET.get(parent_field) in (None, '') else request.GET.get(parent_field) 
    if parent_id == 0:
        # parent item has not yet been chosen (or blank has been selected)
        return render(request, "emptydropdown.html")
    
    if item == State:
        # parent item of State is Country
        # show only states belonging to the chosen country
        items = State.objects.filter(state_in_country_id=parent_id, deleted=False).order_by('item_name')
    
    if item == Suburb:
        # parent item of Suburb is State
        # show only suburbs belonging to the chosen state
        items = Suburb.objects.filter(suburb_in_state_id=parent_id, deleted=False).order_by('item_name')
    return render(request, 'dependentdropdown.html', context={'items': items})
...
def load_states_for_suburbform(request):
    return load_dropdowns(request, State, 'suburb_in_country')
python django forms dropdown modelchoicefield
1个回答
0
投票

解决方案是在

SuburbForm
末尾附加一个if语句:

class SuburbForm(forms.ModelForm):

    # separately define fields for dependent dropdowns
    suburb_in_country = forms.ModelChoiceField(queryset=Country.objects.filter(deleted=False),widget=forms.Select(attrs={"hx-get": "load_states_for_suburbform/", "hx-target": "#id_suburb_in_state"}),label="Country")

    # THE FOLLOWING VARIABLE RESULTS IN A BLANK DROPDOWN LIST WHICH CHANGES TO A FILTERED LIST ON ADD NEW FORM BUT REMAINS BLANK ON UPDATE FORM - SEE __init__ BELOW
    suburb_in_state = forms.ModelChoiceField(queryset=State.objects.none(),label="State")
        
    class Meta:
        model = Suburb
        fields = [
            'item_name', 
            'suburb_in_country',
            'suburb_in_state'
        ]

    def __init__(self, *args, **kwargs):
        super(SuburbForm, self).__init__(*args, **kwargs)

        # handle input from dependent dropdowns
        if 'suburb_in_country' in self.data:
            suburb_in_country = int(self.data.get("suburb_in_country"))
            self.fields['suburb_in_state'].queryset = State.objects.filter(state_in_country=suburb_in_country)
        elif self.instance.pk:
            self.fields['suburb_in_state'].queryset = State.objects.filter(state_in_country=self.instance.suburb_in_country)
© www.soinside.com 2019 - 2024. All rights reserved.