在ModelChoiceField中添加多个标签-Django

时间:2019-12-12 12:23:06

标签: django django-forms

我有这种模型:

class Cities(models.Model):
    country = models.CharField(max_length=45, blank=True, null=True)
    city = models.CharField(max_length=45, blank=True, null=True)

    def get_city_name(self):
        if self.sub_species:
            return str(self.country) + " " + str(self.city)

通过我的模型中的示例数据:

France Paris
France Lyon
France Marseille
Germany Berlin
Germany Bonn

views.py

filter_drop_down_menu_city = CityNameForm()

forms.py

class CityNameChoiceField(forms.ModelChoiceField):
    """
    CityNameChoiceField Class
    """

    def label_from_instance(self, obj):
        """
        This function return the label of the instance
        :param obj:
        :return:
        """
        return obj.get_city_name()


class CityNameForm(forms.Form):
    """
    CityNameForm Class
    """
    cityName = CityNameChoiceField(
        queryset=Cities.objects.order_by('country', 'city'),
        empty_label="(ALL Cities)",
        help_text="",
        required=False,
        label='Cities',
    )

在我的模板中,我的选择字段呈现之前列出的城市列表。

但是我想要那种选择渲染:

France
France Paris
France Lyon
France Marseille
Germany
Germany Berlin
Germany Bonn

用户也可以选择一个国家(然后我可以选择城市)

2 个答案:

答案 0 :(得分:1)

您可以通过更改ModelChoiceField.iterator进行一些魔术操作,但是该属性未记录在案,使用后果自负。

否则,我认为您需要编写自定义ChoiceField

class ModelChoiceIterator(forms.models.ModelChoiceIterator):

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

        self.seen = set()

    def __iter__(self):
        for id, label in super().__iter__():
            country = label.split(' ')[0]

            if country not in self.seen:
                yield (id, country)
                self.seen.add(country)

            yield (id, label)


class CityNameChoiceField(forms.ModelChoiceField):
    iterator = ModelChoiceIterator

    def label_from_instance(self, obj):
        return obj.get_city_name()

答案 1 :(得分:1)

有一种更简单的方法,只需按照documentation构造选择即可实现所需的目标。祝你好运:)

def cities_as_choices():
    choices = []
    for country in models.Cities.objects.values('country').distinct():
        new_country = []
        cities = []
        new_country.append(country.get('country'))

        for city in models.Cities.objects.filter(country=country.get('country')):
            cities.append([city.pk, city.city])

        new_country.append(cities)
        choices.append(new_country)

    return choices


class CityNameForm(forms.Form):
    """
    CityNameForm Class
    """

    def __init__(self, *args, **kwargs):
        super(CityNameForm, self).__init__(*args, **kwargs)
        self.fields['cityName'].choices = cities_as_choices()

    cityName = forms.ChoiceField(
        choices=cities_as_choices(),
        help_text="",
        required=False,
        label='Cities',
    )